]> git.ipfire.org Git - thirdparty/git.git/commitdiff
sparse-checkout: write using lockfile
authorDerrick Stolee <dstolee@microsoft.com>
Thu, 21 Nov 2019 22:04:48 +0000 (22:04 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 22 Nov 2019 07:11:45 +0000 (16:11 +0900)
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>
builtin/sparse-checkout.c
t/t1091-sparse-checkout-builtin.sh

index a11ea65599f2c0e5fcfec358cb1b63585398aa4b..9a620ff014e739319beeb998a8e4acca310440a8 100644 (file)
@@ -170,25 +170,32 @@ static int write_patterns_and_update(struct pattern_list *pl)
 {
        char *sparse_filename;
        FILE *fp;
+       int fd;
+       struct lock_file lk = LOCK_INIT;
        int result;
 
-       result = update_working_directory(pl);
+       sparse_filename = get_sparse_checkout_filename();
+       fd = hold_lock_file_for_update(&lk, sparse_filename,
+                                     LOCK_DIE_ON_ERROR);
 
+       result = update_working_directory(pl);
        if (result) {
+               rollback_lock_file(&lk);
+               free(sparse_filename);
                clear_pattern_list(pl);
                update_working_directory(NULL);
                return result;
        }
 
-       sparse_filename = get_sparse_checkout_filename();
-       fp = fopen(sparse_filename, "w");
+       fp = xfdopen(fd, "w");
 
        if (core_sparse_checkout_cone)
                write_cone_to_file(fp, pl);
        else
                write_patterns_to_file(fp, pl);
 
-       fclose(fp);
+       fflush(fp);
+       commit_lock_file(&lk);
 
        free(sparse_filename);
        clear_pattern_list(pl);
index b8f18e2a09c0cd693b5d87966261ab82e7535ea0..f074b7f3bee746b3b9382ea58e3fa8f7d1707510 100755 (executable)
@@ -277,4 +277,11 @@ test_expect_success 'revert to old sparse-checkout on empty update' '
        )
 '
 
+test_expect_success 'fail when lock is taken' '
+       test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
+       touch repo/.git/info/sparse-checkout.lock &&
+       test_must_fail git -C repo sparse-checkout set deep 2>err &&
+       test_i18ngrep "File exists" err
+'
+
 test_done