Skip to content

Commit d7fc0f5

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 8f3909c commit d7fc0f5

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
@@ -308,6 +308,8 @@ static int write_patterns_and_update(struct pattern_list *pl)
308308
{
309309
char *sparse_filename;
310310
FILE *fp;
311+
int fd;
312+
struct lock_file lk = LOCK_INIT;
311313
int result;
312314

313315
if (!core_apply_sparse_checkout) {
@@ -317,21 +319,28 @@ static int write_patterns_and_update(struct pattern_list *pl)
317319

318320
result = update_working_directory(pl);
319321

322+
sparse_filename = get_sparse_checkout_filename();
323+
fd = hold_lock_file_for_update(&lk, sparse_filename,
324+
LOCK_DIE_ON_ERROR);
325+
326+
result = update_working_directory(pl);
320327
if (result) {
328+
rollback_lock_file(&lk);
329+
free(sparse_filename);
321330
clear_pattern_list(pl);
322331
update_working_directory(NULL);
323332
return result;
324333
}
325334

326-
sparse_filename = get_sparse_checkout_filename();
327-
fp = fopen(sparse_filename, "w");
335+
fp = fdopen(fd, "w");
328336

329337
if (core_sparse_checkout_cone)
330338
write_cone_to_file(fp, pl);
331339
else
332340
write_patterns_to_file(fp, pl);
333341

334-
fclose(fp);
342+
fflush(fp);
343+
commit_lock_file(&lk);
335344

336345
free(sparse_filename);
337346
clear_pattern_list(pl);

t/t1091-sparse-checkout-builtin.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,11 @@ test_expect_success 'revert to old sparse-checkout on bad update' '
262262
test_cmp dir expect
263263
'
264264

265+
test_expect_success 'fail when lock is taken' '
266+
test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
267+
touch repo/.git/info/sparse-checkout.lock &&
268+
test_must_fail git -C repo sparse-checkout set deep 2>err &&
269+
test_i18ngrep "File exists" err
270+
'
271+
265272
test_done

0 commit comments

Comments
 (0)