Skip to content

Commit fb10ca5

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 99dfa6f commit fb10ca5

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

builtin/sparse-checkout.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,25 +170,32 @@ static int write_patterns_and_update(struct pattern_list *pl)
170170
{
171171
char *sparse_filename;
172172
FILE *fp;
173+
int fd;
174+
struct lock_file lk = LOCK_INIT;
173175
int result;
174176

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);
176180

181+
result = update_working_directory(pl);
177182
if (result) {
183+
rollback_lock_file(&lk);
184+
free(sparse_filename);
178185
clear_pattern_list(pl);
179186
update_working_directory(NULL);
180187
return result;
181188
}
182189

183-
sparse_filename = get_sparse_checkout_filename();
184-
fp = fopen(sparse_filename, "w");
190+
fp = xfdopen(fd, "w");
185191

186192
if (core_sparse_checkout_cone)
187193
write_cone_to_file(fp, pl);
188194
else
189195
write_patterns_to_file(fp, pl);
190196

191-
fclose(fp);
197+
fflush(fp);
198+
commit_lock_file(&lk);
192199

193200
free(sparse_filename);
194201
clear_pattern_list(pl);

t/t1091-sparse-checkout-builtin.sh

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

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+
280287
test_done

0 commit comments

Comments
 (0)