summaryrefslogtreecommitdiff
path: root/t/t2501-cwd-empty.sh
blob: b1182390ba388dcac48afef716eab002bdc8188a (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
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
#!/bin/sh

test_description='Test handling of the current working directory becoming empty'

. ./test-lib.sh

test_expect_success setup '
	test_commit init &&

	git branch fd_conflict &&

	mkdir -p foo/bar &&
	test_commit foo/bar/baz &&

	git revert HEAD &&
	git tag reverted &&

	git checkout fd_conflict &&
	mkdir dirORfile &&
	test_commit dirORfile/foo &&

	git rm -r dirORfile &&
	echo not-a-directory >dirORfile &&
	git add dirORfile &&
	git commit -m dirORfile &&

	git switch -c df_conflict HEAD~1 &&
	test_commit random_file &&

	git switch -c undo_fd_conflict fd_conflict &&
	git revert HEAD
'

test_incidental_dir_removal () {
	works=$1 &&
	shift &&

	test_when_finished "git reset --hard" &&

	git checkout foo/bar/baz^{commit} &&
	test_path_is_dir foo/bar &&

	(
		cd foo &&
		"$@" &&

		# Although we want pwd & git status to pass, test for existing
		# rather than desired behavior.
		if test "$works" = "success"
		then
			test-tool getcwd &&
			git status --porcelain
		else
			! test-tool getcwd &&
			test_might_fail git status --porcelain
		fi
	) &&
	test_path_is_missing foo/bar/baz &&
	test_path_is_missing foo/bar &&

	# Although we want dir to be present, test for existing rather
	# than desired behavior.
	if test "$works" = "success"
	then
		test_path_is_dir foo
	else
		test_path_is_missing foo
	fi
}

test_required_dir_removal () {
	works=$1 &&
	shift &&

	git checkout df_conflict^{commit} &&
	test_when_finished "git clean -fdx" &&

	(
		cd dirORfile &&

		# We'd like for the command to fail (much as it would if there
		# was an untracked file there), and for the index and worktree
		# to be left clean with pwd and git status working afterwards.
		# But test for existing rather than desired behavior.
		if test "$works" = "success"
		then
			test_must_fail "$@" 2>../error &&
			grep "Refusing to remove.*current working directory" ../error &&

			git diff --exit-code HEAD &&

			test-tool getcwd &&
			git status --porcelain
		else
			"$@" &&
			! test-tool getcwd &&
			test_might_fail git status --porcelain
		fi
	) &&

	# Although we want dirORfile to be present, test for existing rather
	# than desired behavior.
	if test "$works" = "success"
	then
		test_path_is_dir dirORfile
	else
		test_path_is_file dirORfile
	fi
}

test_expect_success 'checkout does not clean cwd incidentally' '
	test_incidental_dir_removal success git checkout init
'

test_expect_success 'checkout fails if cwd needs to be removed' '
	test_required_dir_removal success git checkout fd_conflict
'

test_expect_success 'reset --hard does not clean cwd incidentally' '
	test_incidental_dir_removal success git reset --hard init
'

test_expect_success 'reset --hard fails if cwd needs to be removed' '
	test_required_dir_removal success git reset --hard fd_conflict
'

test_expect_success 'merge does not clean cwd incidentally' '
	test_incidental_dir_removal success git merge reverted
'

# This file uses some simple merges where
#   Base: 'dirORfile/' exists
#   Side1: random other file changed
#   Side2: 'dirORfile/' removed, 'dirORfile' added
# this should resolve cleanly, but merge-recursive throws merge conflicts
# because it's dumb.  Add a special test for checking merge-recursive (and
# merge-ort), then after this just hard require ort for all remaining tests.
#
test_expect_success 'merge fails if cwd needs to be removed; recursive friendly' '
	git checkout foo/bar/baz &&
	test_when_finished "git clean -fdx" &&

	mkdir dirORfile &&
	(
		cd dirORfile &&

		test_must_fail git merge fd_conflict 2>../error
	) &&

	test_path_is_dir dirORfile &&
	grep "Refusing to remove the current working directory" error
'

GIT_TEST_MERGE_ALGORITHM=ort

test_expect_success 'merge fails if cwd needs to be removed' '
	test_required_dir_removal success git merge fd_conflict
'

test_expect_success 'cherry-pick does not clean cwd incidentally' '
	test_incidental_dir_removal success git cherry-pick reverted
'

test_expect_success 'cherry-pick fails if cwd needs to be removed' '
	test_required_dir_removal success git cherry-pick fd_conflict
'

test_expect_success 'rebase does not clean cwd incidentally' '
	test_incidental_dir_removal failure git rebase reverted
'

test_expect_success 'rebase fails if cwd needs to be removed' '
	test_required_dir_removal failure git rebase fd_conflict
'

test_expect_success 'revert does not clean cwd incidentally' '
	test_incidental_dir_removal success git revert HEAD
'

test_expect_success 'revert fails if cwd needs to be removed' '
	test_required_dir_removal success git revert undo_fd_conflict
'

test_expect_success 'rm does not clean cwd incidentally' '
	test_incidental_dir_removal failure git rm bar/baz.t
'

test_expect_success 'apply does not remove cwd incidentally' '
	git diff HEAD HEAD~1 >patch &&
	test_incidental_dir_removal failure git apply ../patch
'

test_incidental_untracked_dir_removal () {
	works=$1 &&
	shift &&

	test_when_finished "git reset --hard" &&

	git checkout foo/bar/baz^{commit} &&
	mkdir -p untracked &&
	mkdir empty
	>untracked/random &&

	(
		cd untracked &&
		"$@" &&

		# Although we want pwd & git status to pass, test for existing
		# rather than desired behavior.
		if test "$works" = "success"
		then
			test-tool getcwd &&
			git status --porcelain
		else
			! test-tool getcwd &&
			test_might_fail git status --porcelain
		fi
	) &&
	test_path_is_missing empty &&
	test_path_is_missing untracked/random &&

	# Although we want dir to be present, test for existing rather
	# than desired behavior.
	if test "$works" = "success"
	then
		test_path_is_dir untracked
	else
		test_path_is_missing untracked
	fi
}

test_expect_success 'clean does not remove cwd incidentally' '
	test_incidental_untracked_dir_removal success \
		git -C .. clean -fd -e warnings . >warnings &&
	grep "Refusing to remove current working directory" warnings
'

test_expect_success 'stash does not remove cwd incidentally' '
	test_incidental_untracked_dir_removal failure \
		git stash --include-untracked
'

test_expect_success '`rm -rf dir` only removes a subset of dir' '
	test_when_finished "rm -rf a/" &&

	mkdir -p a/b/c &&
	>a/b/c/untracked &&
	>a/b/c/tracked &&
	git add a/b/c/tracked &&

	(
		cd a/b &&
		git rm -rf ../b
	) &&

	test_path_is_dir a/b &&
	test_path_is_missing a/b/c/tracked &&
	test_path_is_file a/b/c/untracked
'

test_expect_success '`rm -rf dir` even with only tracked files will remove something else' '
	test_when_finished "rm -rf a/" &&

	mkdir -p a/b/c &&
	>a/b/c/tracked &&
	git add a/b/c/tracked &&

	(
		cd a/b &&
		git rm -rf ../b
	) &&

	test_path_is_missing a/b/c/tracked &&
	## We would prefer if a/b was still present, though empty, since it
	## was the current working directory
	#test_path_is_dir a/b
	## But the current behavior is that it not only deletes the directory
	## a/b as requested, but also goes and deletes a
	test_path_is_missing a
'

test_expect_success 'git version continues working from a deleted dir' '
	mkdir tmp &&
	(
		cd tmp &&
		rm -rf ../tmp &&
		git version
	)
'

test_submodule_removal () {
	path_status=$1 &&
	shift &&

	test_status=
	test "$path_status" = dir && test_status=test_must_fail

	# Actually, while path_status=dir && test_status=test_must_fail
	# reflect our desired behavior, current behavior is:
	path_status=missing
	test_status=

	test_when_finished "git reset --hard HEAD~1" &&
	test_when_finished "rm -rf .git/modules/my_submodule" &&

	git checkout foo/bar/baz &&

	git init my_submodule &&
	touch my_submodule/file &&
	git -C my_submodule add file &&
	git -C my_submodule commit -m "initial commit" &&
	git submodule add ./my_submodule &&
	git commit -m "Add the submodule" &&

	(
		cd my_submodule &&
		$test_status "$@"
	) &&

	test_path_is_${path_status} my_submodule
}

test_expect_success 'rm -r with -C leaves submodule if cwd inside' '
	test_submodule_removal dir git -C .. rm -r my_submodule/
'

test_expect_success 'rm -r leaves submodule if cwd inside' '
	test_submodule_removal dir \
		git --git-dir=../.git --work-tree=.. rm -r ../my_submodule/
'

test_expect_success 'rm -rf removes submodule even if cwd inside' '
	test_submodule_removal missing \
		git --git-dir=../.git --work-tree=.. rm -rf ../my_submodule/
'

test_done