]>
Commit | Line | Data |
---|---|---|
8464010f DST |
1 | #!/bin/sh |
2 | # | |
3 | # Copyright (c) 2008 Johannes E. Schindelin | |
4 | # | |
5 | ||
6 | test_description='prune' | |
966b4be2 | 7 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
334afbc7 JS |
8 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
9 | ||
8464010f DST |
10 | . ./test-lib.sh |
11 | ||
98df233e CB |
12 | day=$((60*60*24)) |
13 | week=$(($day*7)) | |
14 | ||
15 | add_blob() { | |
16 | before=$(git count-objects | sed "s/ .*//") && | |
17 | BLOB=$(echo aleph_0 | git hash-object -w --stdin) && | |
18 | BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") && | |
8ddfce71 | 19 | test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 20 | test_path_is_file $BLOB_FILE && |
0e496492 | 21 | test-tool chmtime =+0 $BLOB_FILE |
98df233e CB |
22 | } |
23 | ||
8464010f | 24 | test_expect_success setup ' |
1fa9cf6e | 25 | >file && |
8464010f DST |
26 | git add file && |
27 | test_tick && | |
28 | git commit -m initial && | |
29 | git gc | |
8464010f DST |
30 | ' |
31 | ||
69747653 EW |
32 | test_expect_success 'bare repo prune is quiet without $GIT_DIR/objects/pack' ' |
33 | git clone -q --shared --template= --bare . bare.git && | |
34 | rmdir bare.git/objects/pack && | |
35 | git --git-dir=bare.git prune --no-progress 2>prune.err && | |
36 | test_must_be_empty prune.err && | |
37 | rm -r bare.git prune.err | |
38 | ' | |
39 | ||
8464010f | 40 | test_expect_success 'prune stale packs' ' |
8464010f | 41 | orig_pack=$(echo .git/objects/pack/*.pack) && |
1fa9cf6e HWN |
42 | >.git/objects/tmp_1.pack && |
43 | >.git/objects/tmp_2.pack && | |
0e496492 | 44 | test-tool chmtime =-86501 .git/objects/tmp_1.pack && |
8464010f | 45 | git prune --expire 1.day && |
f1dd90bd JK |
46 | test_path_is_file $orig_pack && |
47 | test_path_is_file .git/objects/tmp_2.pack && | |
48 | test_path_is_missing .git/objects/tmp_1.pack | |
8464010f DST |
49 | ' |
50 | ||
25ee9731 | 51 | test_expect_success 'prune --expire' ' |
98df233e | 52 | add_blob && |
25ee9731 | 53 | git prune --expire=1.hour.ago && |
8ddfce71 | 54 | test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 55 | test_path_is_file $BLOB_FILE && |
0e496492 | 56 | test-tool chmtime =-86500 $BLOB_FILE && |
25ee9731 | 57 | git prune --expire 1.day && |
8ddfce71 | 58 | test $before = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 59 | test_path_is_missing $BLOB_FILE |
25ee9731 JS |
60 | ' |
61 | ||
62 | test_expect_success 'gc: implicit prune --expire' ' | |
98df233e | 63 | add_blob && |
0e496492 | 64 | test-tool chmtime =-$((2*$week-30)) $BLOB_FILE && |
b934207a | 65 | git gc --no-cruft && |
8ddfce71 | 66 | test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 67 | test_path_is_file $BLOB_FILE && |
0e496492 | 68 | test-tool chmtime =-$((2*$week+1)) $BLOB_FILE && |
b934207a | 69 | git gc --no-cruft && |
8ddfce71 | 70 | test $before = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 71 | test_path_is_missing $BLOB_FILE |
25ee9731 JS |
72 | ' |
73 | ||
74 | test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' ' | |
258902ce ÆAB |
75 | test_when_finished "rm -rf repo" && |
76 | git init repo && | |
77 | >repo/.git/config && | |
78 | git -C repo config gc.pruneExpire invalid && | |
79 | cat >expect <<-\EOF && | |
80 | error: Invalid gc.pruneexpire: '\''invalid'\'' | |
81 | fatal: bad config variable '\''gc.pruneexpire'\'' in file '\''.git/config'\'' at line 2 | |
82 | EOF | |
83 | test_must_fail git -C repo gc 2>actual && | |
84 | test_cmp expect actual | |
25ee9731 JS |
85 | ' |
86 | ||
87 | test_expect_success 'gc: start with ok gc.pruneExpire' ' | |
25ee9731 | 88 | git config gc.pruneExpire 2.days.ago && |
b934207a | 89 | git gc --no-cruft |
25ee9731 JS |
90 | ' |
91 | ||
0c62705a | 92 | test_expect_success 'prune: prune nonsense parameters' ' |
0c62705a MB |
93 | test_must_fail git prune garbage && |
94 | test_must_fail git prune --- && | |
95 | test_must_fail git prune --no-such-option | |
0c62705a MB |
96 | ' |
97 | ||
98 | test_expect_success 'prune: prune unreachable heads' ' | |
0c62705a | 99 | git config core.logAllRefUpdates false && |
d491f5ea | 100 | >file2 && |
0c62705a MB |
101 | git add file2 && |
102 | git commit -m temporary && | |
103 | tmp_head=$(git rev-list -1 HEAD) && | |
104 | git reset HEAD^ && | |
d491f5ea | 105 | git reflog expire --all && |
0c62705a MB |
106 | git prune && |
107 | test_must_fail git reset $tmp_head -- | |
0c62705a MB |
108 | ' |
109 | ||
c40fdd01 | 110 | test_expect_success 'prune: do not prune detached HEAD with no reflog' ' |
c40fdd01 MK |
111 | git checkout --detach --quiet && |
112 | git commit --allow-empty -m "detached commit" && | |
d491f5ea | 113 | git reflog expire --all && |
c40fdd01 | 114 | git prune -n >prune_actual && |
1c5e94f4 | 115 | test_must_be_empty prune_actual |
c40fdd01 MK |
116 | ' |
117 | ||
118 | test_expect_success 'prune: prune former HEAD after checking out branch' ' | |
cc80c95f | 119 | head_oid=$(git rev-parse HEAD) && |
966b4be2 | 120 | git checkout --quiet main && |
d491f5ea | 121 | git reflog expire --all && |
c40fdd01 | 122 | git prune -v >prune_actual && |
cc80c95f | 123 | grep "$head_oid" prune_actual |
c40fdd01 MK |
124 | ' |
125 | ||
fe308f53 | 126 | test_expect_success 'prune: do not prune heads listed as an argument' ' |
1fa9cf6e | 127 | >file2 && |
0c62705a MB |
128 | git add file2 && |
129 | git commit -m temporary && | |
130 | tmp_head=$(git rev-list -1 HEAD) && | |
131 | git reset HEAD^ && | |
132 | git prune -- $tmp_head && | |
133 | git reset $tmp_head -- | |
0c62705a MB |
134 | ' |
135 | ||
58e9d9d4 | 136 | test_expect_success 'gc --no-prune' ' |
98df233e | 137 | add_blob && |
0e496492 | 138 | test-tool chmtime =-$((5001*$day)) $BLOB_FILE && |
58e9d9d4 | 139 | git config gc.pruneExpire 2.days.ago && |
b934207a | 140 | git gc --no-prune --no-cruft && |
8ddfce71 | 141 | test 1 = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 142 | test_path_is_file $BLOB_FILE |
58e9d9d4 JS |
143 | ' |
144 | ||
145 | test_expect_success 'gc respects gc.pruneExpire' ' | |
58e9d9d4 | 146 | git config gc.pruneExpire 5002.days.ago && |
b934207a | 147 | git gc --no-cruft && |
f1dd90bd | 148 | test_path_is_file $BLOB_FILE && |
58e9d9d4 | 149 | git config gc.pruneExpire 5000.days.ago && |
b934207a | 150 | git gc --no-cruft && |
f1dd90bd | 151 | test_path_is_missing $BLOB_FILE |
58e9d9d4 JS |
152 | ' |
153 | ||
154 | test_expect_success 'gc --prune=<date>' ' | |
98df233e | 155 | add_blob && |
0e496492 | 156 | test-tool chmtime =-$((5001*$day)) $BLOB_FILE && |
b934207a | 157 | git gc --prune=5002.days.ago --no-cruft && |
f1dd90bd | 158 | test_path_is_file $BLOB_FILE && |
b934207a | 159 | git gc --prune=5000.days.ago --no-cruft && |
f1dd90bd | 160 | test_path_is_missing $BLOB_FILE |
58e9d9d4 JS |
161 | ' |
162 | ||
cbf731ed | 163 | test_expect_success 'gc --prune=never' ' |
cbf731ed | 164 | add_blob && |
b934207a | 165 | git gc --prune=never --no-cruft && |
f1dd90bd | 166 | test_path_is_file $BLOB_FILE && |
b934207a | 167 | git gc --prune=now --no-cruft && |
f1dd90bd | 168 | test_path_is_missing $BLOB_FILE |
cbf731ed AS |
169 | ' |
170 | ||
171 | test_expect_success 'gc respects gc.pruneExpire=never' ' | |
cbf731ed AS |
172 | git config gc.pruneExpire never && |
173 | add_blob && | |
b934207a | 174 | git gc --no-cruft && |
f1dd90bd | 175 | test_path_is_file $BLOB_FILE && |
cbf731ed | 176 | git config gc.pruneExpire now && |
b934207a | 177 | git gc --no-cruft && |
f1dd90bd | 178 | test_path_is_missing $BLOB_FILE |
cbf731ed AS |
179 | ' |
180 | ||
181 | test_expect_success 'prune --expire=never' ' | |
cbf731ed AS |
182 | add_blob && |
183 | git prune --expire=never && | |
f1dd90bd | 184 | test_path_is_file $BLOB_FILE && |
cbf731ed | 185 | git prune && |
f1dd90bd | 186 | test_path_is_missing $BLOB_FILE |
cbf731ed AS |
187 | ' |
188 | ||
98df233e CB |
189 | test_expect_success 'gc: prune old objects after local clone' ' |
190 | add_blob && | |
0e496492 | 191 | test-tool chmtime =-$((2*$week+1)) $BLOB_FILE && |
98df233e CB |
192 | git clone --no-hardlinks . aclone && |
193 | ( | |
194 | cd aclone && | |
8ddfce71 | 195 | test 1 = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 196 | test_path_is_file $BLOB_FILE && |
b934207a | 197 | git gc --prune --no-cruft && |
8ddfce71 | 198 | test 0 = $(git count-objects | sed "s/ .*//") && |
f1dd90bd | 199 | test_path_is_missing $BLOB_FILE |
98df233e CB |
200 | ) |
201 | ' | |
202 | ||
543c5caa | 203 | test_expect_success 'garbage report in count-objects -v' ' |
f813e9ea | 204 | test_when_finished "rm -f .git/objects/pack/fake*" && |
e6d65c9a | 205 | test_when_finished "rm -f .git/objects/pack/foo*" && |
1fa9cf6e HWN |
206 | >.git/objects/pack/foo && |
207 | >.git/objects/pack/foo.bar && | |
208 | >.git/objects/pack/foo.keep && | |
209 | >.git/objects/pack/foo.pack && | |
210 | >.git/objects/pack/fake.bar && | |
211 | >.git/objects/pack/fake.keep && | |
212 | >.git/objects/pack/fake.pack && | |
213 | >.git/objects/pack/fake.idx && | |
214 | >.git/objects/pack/fake2.keep && | |
215 | >.git/objects/pack/fake3.idx && | |
543c5caa NTND |
216 | git count-objects -v 2>stderr && |
217 | grep "index file .git/objects/pack/fake.idx is too small" stderr && | |
218 | grep "^warning:" stderr | sort >actual && | |
219 | cat >expected <<\EOF && | |
220 | warning: garbage found: .git/objects/pack/fake.bar | |
221 | warning: garbage found: .git/objects/pack/foo | |
222 | warning: garbage found: .git/objects/pack/foo.bar | |
235e8d59 | 223 | warning: no corresponding .idx or .pack: .git/objects/pack/fake2.keep |
543c5caa NTND |
224 | warning: no corresponding .idx: .git/objects/pack/foo.keep |
225 | warning: no corresponding .idx: .git/objects/pack/foo.pack | |
226 | warning: no corresponding .pack: .git/objects/pack/fake3.idx | |
227 | EOF | |
228 | test_cmp expected actual | |
229 | ' | |
230 | ||
478f34d2 | 231 | test_expect_success 'clean pack garbage with gc' ' |
e6d65c9a DK |
232 | test_when_finished "rm -f .git/objects/pack/fake*" && |
233 | test_when_finished "rm -f .git/objects/pack/foo*" && | |
1fa9cf6e HWN |
234 | >.git/objects/pack/foo.keep && |
235 | >.git/objects/pack/foo.pack && | |
236 | >.git/objects/pack/fake.idx && | |
237 | >.git/objects/pack/fake2.keep && | |
238 | >.git/objects/pack/fake2.idx && | |
239 | >.git/objects/pack/fake3.keep && | |
b934207a | 240 | git gc --no-cruft && |
e6d65c9a DK |
241 | git count-objects -v 2>stderr && |
242 | grep "^warning:" stderr | sort >actual && | |
243 | cat >expected <<\EOF && | |
244 | warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep | |
245 | warning: no corresponding .idx: .git/objects/pack/foo.keep | |
246 | warning: no corresponding .idx: .git/objects/pack/foo.pack | |
247 | EOF | |
248 | test_cmp expected actual | |
249 | ' | |
250 | ||
eab3296c | 251 | test_expect_success 'prune .git/shallow' ' |
cc80c95f JK |
252 | oid=$(echo hi|git commit-tree HEAD^{tree}) && |
253 | echo $oid >.git/shallow && | |
eab3296c | 254 | git prune --dry-run >out && |
cc80c95f JK |
255 | grep $oid .git/shallow && |
256 | grep $oid out && | |
eab3296c | 257 | git prune && |
f1dd90bd | 258 | test_path_is_missing .git/shallow |
eab3296c NTND |
259 | ' |
260 | ||
d55a30bb | 261 | test_expect_success 'prune .git/shallow when there are no loose objects' ' |
cc80c95f JK |
262 | oid=$(echo hi|git commit-tree HEAD^{tree}) && |
263 | echo $oid >.git/shallow && | |
264 | git update-ref refs/heads/shallow-tip $oid && | |
d55a30bb JK |
265 | git repack -ad && |
266 | # verify assumption that all loose objects are gone | |
267 | git count-objects | grep ^0 && | |
268 | git prune && | |
cc80c95f | 269 | echo $oid >expect && |
d55a30bb JK |
270 | test_cmp expect .git/shallow |
271 | ' | |
272 | ||
b0a42642 JM |
273 | test_expect_success 'prune: handle alternate object database' ' |
274 | test_create_repo A && | |
275 | git -C A commit --allow-empty -m "initial commit" && | |
276 | git clone --shared A B && | |
277 | git -C B commit --allow-empty -m "next commit" && | |
278 | git -C B prune | |
279 | ' | |
280 | ||
be489d02 NTND |
281 | test_expect_success 'prune: handle index in multiple worktrees' ' |
282 | git worktree add second-worktree && | |
283 | echo "new blob for second-worktree" >second-worktree/blob && | |
284 | git -C second-worktree add blob && | |
285 | git prune --expire=now && | |
286 | git -C second-worktree show :blob >actual && | |
287 | test_cmp second-worktree/blob actual | |
288 | ' | |
289 | ||
d0c39a49 NTND |
290 | test_expect_success 'prune: handle HEAD in multiple worktrees' ' |
291 | git worktree add --detach third-worktree && | |
292 | echo "new blob for third-worktree" >third-worktree/blob && | |
293 | git -C third-worktree add blob && | |
294 | git -C third-worktree commit -m "third" && | |
295 | rm .git/worktrees/third-worktree/index && | |
296 | test_must_fail git -C third-worktree show :blob && | |
297 | git prune --expire=now && | |
298 | git -C third-worktree show HEAD:blob >actual && | |
299 | test_cmp third-worktree/blob actual | |
300 | ' | |
301 | ||
acd9544a NTND |
302 | test_expect_success 'prune: handle HEAD reflog in multiple worktrees' ' |
303 | git config core.logAllRefUpdates true && | |
304 | echo "lost blob for third-worktree" >expected && | |
305 | ( | |
306 | cd third-worktree && | |
307 | cat ../expected >blob && | |
308 | git add blob && | |
309 | git commit -m "second commit in third" && | |
f222bd34 | 310 | git clean -f && # Remove untracked left behind by deleting index |
acd9544a NTND |
311 | git reset --hard HEAD^ |
312 | ) && | |
313 | git prune --expire=now && | |
cc80c95f JK |
314 | oid=`git hash-object expected` && |
315 | git -C third-worktree show "$oid" >actual && | |
acd9544a NTND |
316 | test_cmp expected actual |
317 | ' | |
318 | ||
8ab5aa4b JH |
319 | test_expect_success 'prune: handle expire option correctly' ' |
320 | test_must_fail git prune --expire 2>error && | |
6789275d | 321 | test_grep "requires a value" error && |
8ab5aa4b JH |
322 | |
323 | test_must_fail git prune --expire=nyah 2>error && | |
6789275d | 324 | test_grep "malformed expiration" error && |
8ab5aa4b JH |
325 | |
326 | git prune --no-expire | |
327 | ' | |
328 | ||
fe6f2b08 JK |
329 | test_expect_success 'trivial prune with bitmaps enabled' ' |
330 | git repack -adb && | |
331 | blob=$(echo bitmap-unreachable-blob | git hash-object -w --stdin) && | |
332 | git prune --expire=now && | |
333 | git cat-file -e HEAD && | |
334 | test_must_fail git cat-file -e $blob | |
335 | ' | |
336 | ||
2ba582ba JK |
337 | test_expect_success 'old reachable-from-recent retained with bitmaps' ' |
338 | git repack -adb && | |
339 | to_drop=$(echo bitmap-from-recent-1 | git hash-object -w --stdin) && | |
340 | test-tool chmtime -86400 .git/objects/$(test_oid_to_path $to_drop) && | |
341 | to_save=$(echo bitmap-from-recent-2 | git hash-object -w --stdin) && | |
342 | test-tool chmtime -86400 .git/objects/$(test_oid_to_path $to_save) && | |
343 | tree=$(printf "100644 blob $to_save\tfile\n" | git mktree) && | |
344 | test-tool chmtime -86400 .git/objects/$(test_oid_to_path $tree) && | |
345 | commit=$(echo foo | git commit-tree $tree) && | |
346 | git prune --expire=12.hours.ago && | |
347 | git cat-file -e $commit && | |
348 | git cat-file -e $tree && | |
349 | git cat-file -e $to_save && | |
350 | test_must_fail git cat-file -e $to_drop | |
351 | ' | |
352 | ||
4dc16e2c TB |
353 | test_expect_success 'gc.recentObjectsHook' ' |
354 | add_blob && | |
355 | test-tool chmtime =-86500 $BLOB_FILE && | |
356 | ||
357 | write_script precious-objects <<-EOF && | |
358 | echo $BLOB | |
359 | EOF | |
360 | test_config gc.recentObjectsHook ./precious-objects && | |
361 | ||
362 | git prune --expire=now && | |
363 | ||
364 | git cat-file -p $BLOB | |
365 | ' | |
366 | ||
8464010f | 367 | test_done |