Skip to content

Commit a879c5b

Browse files
derrickstoleegitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent efd9c53 commit a879c5b

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

builtin/sparse-checkout.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,25 +306,34 @@ static int write_patterns_and_update(struct pattern_list *pl)
306306
{
307307
char *sparse_filename;
308308
FILE *fp;
309+
int fd;
310+
struct lock_file lk = LOCK_INIT;
309311
int result;
310312

311313
result = update_working_directory(pl);
312314

315+
sparse_filename = get_sparse_checkout_filename();
316+
fd = hold_lock_file_for_update(&lk, sparse_filename,
317+
LOCK_DIE_ON_ERROR);
318+
319+
result = update_working_directory(pl);
313320
if (result) {
321+
rollback_lock_file(&lk);
322+
free(sparse_filename);
314323
clear_pattern_list(pl);
315324
update_working_directory(NULL);
316325
return result;
317326
}
318327

319-
sparse_filename = get_sparse_checkout_filename();
320-
fp = fopen(sparse_filename, "w");
328+
fp = xfdopen(fd, "w");
321329

322330
if (core_sparse_checkout_cone)
323331
write_cone_to_file(fp, pl);
324332
else
325333
write_patterns_to_file(fp, pl);
326334

327-
fclose(fp);
335+
fflush(fp);
336+
commit_lock_file(&lk);
328337

329338
free(sparse_filename);
330339
clear_pattern_list(pl);

t/t1091-sparse-checkout-builtin.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,11 @@ test_expect_success 'revert to old sparse-checkout on empty update' '
276276
)
277277
'
278278

279+
test_expect_success 'fail when lock is taken' '
280+
test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
281+
touch repo/.git/info/sparse-checkout.lock &&
282+
test_must_fail git -C repo sparse-checkout set deep 2>err &&
283+
test_i18ngrep "File exists" err
284+
'
285+
279286
test_done

0 commit comments

Comments
 (0)