sparse-checkout: write using lockfile
If two 'git sparse-checkout set' subcommands are launched at the same time, the behavior can be unexpected as they compete to write the sparse-checkout file and update the working directory. Take a lockfile around the writes to the sparse-checkout file. In addition, acquire this lock around the working directory update to avoid two commands updating the working directory in different ways. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Derrick Stolee committed
Nov 21, 2019 at 22:04 UTC
fb10ca5b54362e6f860e1e9049e03924fcf5f05b
2 files changed
+18
-4
builtin/sparse-checkout.c
+11
-4
@@ -170,25 +170,32 @@ static int write_patterns_and_update(struct pattern_list *pl)
170
{
171
char *sparse_filename;
172
FILE *fp;
173
+ int fd;
174
+ struct lock_file lk = LOCK_INIT;
175
int result;
176
175
- result = update_working_directory(pl);
177
+ sparse_filename = get_sparse_checkout_filename();
178
+ fd = hold_lock_file_for_update(&lk, sparse_filename,
179
+ LOCK_DIE_ON_ERROR);
180
181
+ result = update_working_directory(pl);
182
if (result) {
183
+ rollback_lock_file(&lk);
184
+ free(sparse_filename);
185
clear_pattern_list(pl);
186
update_working_directory(NULL);
187
return result;
188
}
189
183
- sparse_filename = get_sparse_checkout_filename();
184
- fp = fopen(sparse_filename, "w");
190
+ fp = xfdopen(fd, "w");
191
192
if (core_sparse_checkout_cone)
193
write_cone_to_file(fp, pl);
194
else
195
write_patterns_to_file(fp, pl);
196
191
- fclose(fp);
197
+ fflush(fp);
198
+ commit_lock_file(&lk);
199
200
free(sparse_filename);
201
clear_pattern_list(pl);
t/t1091-sparse-checkout-builtin.sh
+7
@@ -277,4 +277,11 @@ test_expect_success 'revert to old sparse-checkout on empty update' '
277
)
278
'
279
280
+test_expect_success 'fail when lock is taken' '
281
+ test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
282
+ touch repo/.git/info/sparse-checkout.lock &&
283
+ test_must_fail git -C repo sparse-checkout set deep 2>err &&
284
+ test_i18ngrep "File exists" err
285
+'
286
+
287
test_done