summaryrefslogtreecommitdiffstats
path: root/t/t1460-refs-migrate.sh
blob: f7c0783d30ccd61b0fee67c115193b42bb0e2c77 (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
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
#!/bin/sh

test_description='migration of ref storage backends'

GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_migration () {
	git -C "$1" for-each-ref --include-root-refs \
		--format='%(refname) %(objectname) %(symref)' >expect &&
	git -C "$1" refs migrate --ref-format="$2" &&
	git -C "$1" for-each-ref --include-root-refs \
		--format='%(refname) %(objectname) %(symref)' >actual &&
	test_cmp expect actual &&

	git -C "$1" rev-parse --show-ref-format >actual &&
	echo "$2" >expect &&
	test_cmp expect actual
}

test_expect_success 'setup' '
	rm -rf .git &&
	# The migration does not yet support reflogs.
	git config --global core.logAllRefUpdates false
'

test_expect_success "superfluous arguments" '
	test_when_finished "rm -rf repo" &&
	git init repo &&
	test_must_fail git -C repo refs migrate foo 2>err &&
	cat >expect <<-EOF &&
	usage: too many arguments
	EOF
	test_cmp expect err
'

test_expect_success "missing ref storage format" '
	test_when_finished "rm -rf repo" &&
	git init repo &&
	test_must_fail git -C repo refs migrate 2>err &&
	cat >expect <<-EOF &&
	usage: missing --ref-format=<format>
	EOF
	test_cmp expect err
'

test_expect_success "unknown ref storage format" '
	test_when_finished "rm -rf repo" &&
	git init repo &&
	test_must_fail git -C repo refs migrate \
		--ref-format=unknown 2>err &&
	cat >expect <<-EOF &&
	error: unknown ref storage format ${SQ}unknown${SQ}
	EOF
	test_cmp expect err
'

ref_formats="files reftable"
for from_format in $ref_formats
do
	for to_format in $ref_formats
	do
		if test "$from_format" = "$to_format"
		then
			continue
		fi

		test_expect_success "$from_format: migration to same format fails" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_must_fail git -C repo refs migrate \
				--ref-format=$from_format 2>err &&
			cat >expect <<-EOF &&
			error: repository already uses ${SQ}$from_format${SQ} format
			EOF
			test_cmp expect err
		'

		test_expect_success "$from_format -> $to_format: migration with reflog fails" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_config -C repo core.logAllRefUpdates true &&
			test_commit -C repo logged &&
			test_must_fail git -C repo refs migrate \
				--ref-format=$to_format 2>err &&
			cat >expect <<-EOF &&
			error: migrating reflogs is not supported yet
			EOF
			test_cmp expect err
		'

		test_expect_success "$from_format -> $to_format: migration with worktree fails" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			git -C repo worktree add wt &&
			test_must_fail git -C repo refs migrate \
				--ref-format=$to_format 2>err &&
			cat >expect <<-EOF &&
			error: migrating repositories with worktrees is not supported yet
			EOF
			test_cmp expect err
		'

		test_expect_success "$from_format -> $to_format: unborn HEAD" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_migration repo "$to_format"
		'

		test_expect_success "$from_format -> $to_format: single ref" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			test_migration repo "$to_format"
		'

		test_expect_success "$from_format -> $to_format: bare repository" '
			test_when_finished "rm -rf repo repo.git" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			git clone --ref-format=$from_format --mirror repo repo.git &&
			test_migration repo.git "$to_format"
		'

		test_expect_success "$from_format -> $to_format: dangling symref" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			git -C repo symbolic-ref BROKEN_HEAD refs/heads/nonexistent &&
			test_migration repo "$to_format" &&
			echo refs/heads/nonexistent >expect &&
			git -C repo symbolic-ref BROKEN_HEAD >actual &&
			test_cmp expect actual
		'

		test_expect_success "$from_format -> $to_format: broken ref" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			test-tool -C repo ref-store main update-ref "" refs/heads/broken \
				"$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION &&
			test_migration repo "$to_format" &&
			test_oid 001 >expect &&
			git -C repo rev-parse refs/heads/broken >actual &&
			test_cmp expect actual
		'

		test_expect_success "$from_format -> $to_format: pseudo-refs" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			git -C repo update-ref FOO_HEAD HEAD &&
			test_migration repo "$to_format"
		'

		test_expect_success "$from_format -> $to_format: special refs are left alone" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			git -C repo rev-parse HEAD >repo/.git/MERGE_HEAD &&
			git -C repo rev-parse MERGE_HEAD &&
			test_migration repo "$to_format" &&
			test_path_is_file repo/.git/MERGE_HEAD
		'

		test_expect_success "$from_format -> $to_format: a bunch of refs" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&

			test_commit -C repo initial &&
			cat >input <<-EOF &&
			create FOO_HEAD HEAD
			create refs/heads/branch-1 HEAD
			create refs/heads/branch-2 HEAD
			create refs/heads/branch-3 HEAD
			create refs/heads/branch-4 HEAD
			create refs/tags/tag-1 HEAD
			create refs/tags/tag-2 HEAD
			EOF
			git -C repo update-ref --stdin <input &&
			test_migration repo "$to_format"
		'

		test_expect_success "$from_format -> $to_format: dry-run migration does not modify repository" '
			test_when_finished "rm -rf repo" &&
			git init --ref-format=$from_format repo &&
			test_commit -C repo initial &&
			git -C repo refs migrate --dry-run \
				--ref-format=$to_format >output &&
			grep "Finished dry-run migration of refs" output &&
			test_path_is_dir repo/.git/ref_migration.* &&
			echo $from_format >expect &&
			git -C repo rev-parse --show-ref-format >actual &&
			test_cmp expect actual
		'
	done
done

test_expect_success 'migrating from files format deletes backend files' '
	test_when_finished "rm -rf repo" &&
	git init --ref-format=files repo &&
	test_commit -C repo first &&
	git -C repo pack-refs --all &&
	test_commit -C repo second &&
	git -C repo update-ref ORIG_HEAD HEAD &&
	git -C repo rev-parse HEAD >repo/.git/FETCH_HEAD &&

	test_path_is_file repo/.git/HEAD &&
	test_path_is_file repo/.git/ORIG_HEAD &&
	test_path_is_file repo/.git/refs/heads/main &&
	test_path_is_file repo/.git/packed-refs &&

	test_migration repo reftable &&

	echo "ref: refs/heads/.invalid" >expect &&
	test_cmp expect repo/.git/HEAD &&
	echo "this repository uses the reftable format" >expect &&
	test_cmp expect repo/.git/refs/heads &&
	test_path_is_file repo/.git/FETCH_HEAD &&
	test_path_is_missing repo/.git/ORIG_HEAD &&
	test_path_is_missing repo/.git/refs/heads/main &&
	test_path_is_missing repo/.git/logs &&
	test_path_is_missing repo/.git/packed-refs
'

test_expect_success 'migrating from reftable format deletes backend files' '
	test_when_finished "rm -rf repo" &&
	git init --ref-format=reftable repo &&
	test_commit -C repo first &&

	test_path_is_dir repo/.git/reftable &&
	test_migration repo files &&

	test_path_is_missing repo/.git/reftable &&
	echo "ref: refs/heads/main" >expect &&
	test_cmp expect repo/.git/HEAD &&
	test_path_is_file repo/.git/refs/heads/main
'

test_done