summaryrefslogtreecommitdiff
path: root/t/t7706-repack-drop-filtered.sh
blob: cb361158349c13af6bf95ba24895acd4ea9d385a (plain)
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
#!/bin/sh

test_description='git repack --drop-filtered enumerates filtered promisor blobs'

. ./test-lib.sh

# Delete a loose or packed object from "repo".
delete_object () {
	local repo="$1" &&
	local obj="$2" &&
	local path="$repo/.git/objects/$(test_oid_to_path "$obj")" &&
	rm "$path"
}

# Pack the objects into a promisor pack inside "repo". It is a pack
# accompanied by an empty ".promisor" marker file. Objects
# in such a pack are treated as recoverable from the promisor remote.
pack_as_from_promisor () {
	HASH=$(git -C repo pack-objects .git/objects/pack/pack) &&
	>repo/.git/objects/pack/pack-$HASH.promisor &&
	echo $HASH
}

# Write a blob of $1 bytes into "repo", record it as coming from the
# promisor remote, and remove the loose copy so the object is only
# present in the promisor pack.
promisor_blob () {
	test-tool genrandom "$1" "$2" >blob_content &&
	OID=$(git -C repo hash-object -w --stdin <blob_content) &&
	printf "%s\n" "$OID" | pack_as_from_promisor >/dev/null &&
	delete_object repo "$OID" &&
	echo "$OID"
}

# Check option validation before any promisor walk
test_expect_success 'setup plain repo for validation' '
	git init plain &&
	test_commit -C plain initial &&
	git clone --bare plain plain.git &&
	git -C plain.git repack -a -d
'

test_expect_success '--drop-filtered requires --filter' '
	test_must_fail git -C plain.git repack --drop-filtered --dry-run -a 2>err &&
	test_grep "drop-filtered requires --filter" err
'

test_expect_success '--drop-filtered cannot be used with --filter-to' '
	test_must_fail git -C plain.git repack --drop-filtered \
		--filter=blob:limit=1k --filter-to=./filter-out 2>err &&
	test_grep "options .--drop-filtered. and .--filter-to. cannot be used together" err
'

test_expect_success '--dry-run only takes effect with --drop-filtered' '
	test_must_fail git -C plain.git repack --dry-run 2>err &&
	test_grep "dry-run only takes effect with --drop-filtered" err
'

test_expect_success '--drop-filtered requires -a' '
	test_must_fail git -C plain.git repack --drop-filtered \
		--filter=blob:limit=1k --dry-run 2>err &&
	test_grep "drop-filtered requires -a" err
'

test_expect_success '--drop-filtered fails with --write-bitmap-index' '
	test_must_fail git -C plain.git repack --drop-filtered \
		--filter=blob:limit=1k --dry-run -a -b 2>err &&
	test_grep "options .--drop-filtered. and .--write-bitmap-index. cannot be used together" err
'

test_expect_success '--drop-filtered rejects explicit -b even when repack.writeBitmaps=true' '
	test_must_fail git -C plain.git -c repack.writeBitmaps=true \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a -b 2>err &&
	test_grep "options .--drop-filtered. and .--write-bitmap-index. cannot be used together" err
'

test_expect_success '--drop-filtered fails without a promisor remote' '
	test_must_fail git -C plain.git repack --drop-filtered \
		--filter=blob:limit=1k --dry-run -a 2>err &&
	test_grep "drop-filtered requires a promisor remote" err
'

# Enumeration tests using promisor pack
test_expect_success 'setup repo with a promisor remote' '
	rm -rf repo &&
	test_create_repo repo &&
	test_commit -C repo base &&

	# Mark the repo as a partial clone with a promisor remote so the
	# promisor walk and the safety guard are satisfied.
	git -C repo config core.repositoryformatversion 1 &&
	git -C repo config extensions.partialclone origin &&
	git -C repo config remote.origin.promisor true &&
	git -C repo config remote.origin.url "." &&

	BIG=$(promisor_blob big 3072) &&
	SMALL=$(promisor_blob small 512) &&
	echo "$BIG" >big_oid &&
	echo "$SMALL" >small_oid
'

test_expect_success 'promisor blob over the threshold is listed' '
	BIG=$(cat big_oid) &&
	SMALL=$(cat small_oid) &&

	git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a >out &&

	test_grep "$BIG" out &&
	test_grep ! "$SMALL" out
'

test_expect_success 'locally created blob is never listed' '
	BIG=$(cat big_oid) &&

	# Large blob that exists only locally must never be a drop candidate.
	# Dropping it would be unrecoverable.
	test-tool genrandom local 4096 >local_content &&
	LOCAL=$(git -C repo hash-object -w --stdin <local_content) &&

	git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a >out &&

	test_grep "$BIG" out &&
	test_grep ! "$LOCAL" out
'

test_expect_success '--dry-run does not remove the filtered objects' '
	BIG=$(cat big_oid) &&

	git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a >out &&

	# Candidate blob must still be present after a dry run.
	git -C repo cat-file -e "$BIG"
'

test_expect_success '--drop-filtered removes the promisor blob locally' '
	BIG=$(cat big_oid) &&
	SMALL=$(cat small_oid) &&

	git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k -a &&

	git -C repo cat-file --batch-all-objects --batch-check="%(objectname)" >present &&
	test_grep ! "$BIG" present &&
	test_grep "$SMALL" present
'

test_expect_success '--drop-filtered refuses when a merge is in progress' '
	test_when_finished "git -C repo merge --abort || :" &&

	# Create a conflicting merge so wt_status reports it.
	git -C repo checkout -B mergebase base &&
	echo one >repo/conflict.txt &&
	git -C repo add conflict.txt &&
	git -C repo commit -m one &&

	git -C repo checkout -B mergeother base &&
	echo two >repo/conflict.txt &&
	git -C repo add conflict.txt &&
	git -C repo commit -m two &&

	test_must_fail git -C repo merge mergebase &&

	test_must_fail git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a 2>err &&
	test_grep "in progress" err
'

test_expect_success '--drop-filtered refuses to drop an index-referenced blob' '
	# Create a large blob, add it to the index and make it a promisor object
	# so the index references it and enumeration picks it up.
	test-tool genrandom idx 4096 >repo/tracked-big.bin &&
	git -C repo add tracked-big.bin &&
	OID=$(git -C repo rev-parse :tracked-big.bin) &&
	printf "%s\n" "$OID" | pack_as_from_promisor >/dev/null &&
	delete_object repo "$OID" &&

	test_must_fail git -C repo -c repack.writeBitmaps=false \
		repack --drop-filtered --filter=blob:limit=1k --dry-run -a 2>err &&
	test_grep "referenced by the current index" err
'

test_done