There was some semantic conflicts between this series and jk/checkout-index-errors, so I rebased my series on top of that. Also, I'd please ask reviewers to confirm that my descriptor redirection in git_pc() (patch 17) is correct, as I'm not very familiar with the test suite descriptors. Main changes since v2: Patch 10: - Squashed Peff's patch removing an useless function parameter. Patch 11: - Valgrind used to complain about send_one_item() passing uninitialized bytes to a syscall (write(2)). The referred bytes come from the unused positions on oid->hash[], when the hash is SHA-1. Since the workers won't use these bytes, there is no real harm. But the warning could cause confusion and even get in the way of detecting real errors, so I replaced the oidcpy() call with hashcpy(). Patch 16: - Replaced use of the non-portable '\+' in grep with '..*' (in t/lib-parallel-checkout.sh). - Properly quoted function parameters in t/lib-parallel-checkout.sh, as Jonathan pointed out. - In t2080, dropped tests that used git.git as test data, and added two more tests to check clone with parallel-checkout using the artificial repo already created for other tests. - No longer skip clone tests when GIT_TEST_DEFAULT_HASH is sha256. A bug in clone used to make the tests fail with this configuration set to this value, but the bug was fixed in 47ac970309 ("builtin/clone: avoid failure with GIT_DEFAULT_HASH", 2020-09-20). Patch 17: - The test t2081-parallel-checkout-collisions.sh had a bug in which the filter options were being wrongly passed to git. These options were conditionally defined through a shell variable, for which the quoting was wrong. This should have made the test fail but, in fact, another bug (using the arithmetic operator `-eq` for strings), was preventing the problematic section from ever running. These bugs are now fixed, and the test script was also simplified, by making use of the lib-parallel-checkout.sh and eliminating the helper function. - Use "$TEST_ROOT/logger_script" instead of "../logger_script", to be on the safe side. Jeff Hostetler (4): convert: make convert_attrs() and convert structs public convert: add [async_]convert_to_working_tree_ca() variants convert: add get_stream_filter_ca() variant convert: add conv_attrs classification Matheus Tavares (15): entry: extract a header file for entry.c functions entry: make fstat_output() and read_blob_entry() public entry: extract cache_entry update from write_entry() entry: move conv_attrs lookup up to checkout_entry() entry: add checkout_entry_ca() which takes preloaded conv_attrs unpack-trees: add basic support for parallel checkout parallel-checkout: make it truly parallel parallel-checkout: support progress displaying make_transient_cache_entry(): optionally alloc from mem_pool builtin/checkout.c: complete parallel checkout support checkout-index: add parallel checkout support parallel-checkout: add tests for basic operations parallel-checkout: add tests related to clone collisions parallel-checkout: add tests related to .gitattributes ci: run test round with parallel-checkout enabled .gitignore | 1 + Documentation/config/checkout.txt | 21 + Makefile | 2 + apply.c | 1 + builtin.h | 1 + builtin/checkout--helper.c | 142 ++++++ builtin/checkout-index.c | 22 +- builtin/checkout.c | 21 +- builtin/difftool.c | 3 +- cache.h | 34 +- ci/run-build-and-tests.sh | 1 + convert.c | 121 +++-- convert.h | 68 +++ entry.c | 102 ++-- entry.h | 54 ++ git.c | 2 + parallel-checkout.c | 638 ++++++++++++++++++++++++ parallel-checkout.h | 103 ++++ read-cache.c | 12 +- t/README | 4 + t/lib-encoding.sh | 25 + t/lib-parallel-checkout.sh | 46 ++ t/t0028-working-tree-encoding.sh | 25 +- t/t2080-parallel-checkout-basics.sh | 170 +++++++ t/t2081-parallel-checkout-collisions.sh | 98 ++++ t/t2082-parallel-checkout-attributes.sh | 174 +++++++ unpack-trees.c | 22 +- 27 files changed, 1758 insertions(+), 155 deletions(-) create mode 100644 builtin/checkout--helper.c create mode 100644 entry.h create mode 100644 parallel-checkout.c create mode 100644 parallel-checkout.h create mode 100644 t/lib-encoding.sh create mode 100644 t/lib-parallel-checkout.sh create mode 100755 t/t2080-parallel-checkout-basics.sh create mode 100755 t/t2081-parallel-checkout-collisions.sh create mode 100755 t/t2082-parallel-checkout-attributes.sh Range-diff against v2: 1: b9d2a329d3 = 1: dfc3e0fd62 convert: make convert_attrs() and convert structs public 2: 313c3bcbeb = 2: c5fbd1e16d convert: add [async_]convert_to_working_tree_ca() variants 3: 29bbdb78e9 = 3: c77b16f694 convert: add get_stream_filter_ca() variant 4: a1cf5df961 = 4: 18c3f4247e convert: add conv_attrs classification 5: 25b311745a = 5: 2caa2c4345 entry: extract a header file for entry.c functions 6: dbee09e936 = 6: bfa52df9e2 entry: make fstat_output() and read_blob_entry() public 7: b61b5c44f0 = 7: 91ef17f533 entry: extract cache_entry update from write_entry() 8: 667ad0dea7 = 8: 81e03baab1 entry: move conv_attrs lookup up to checkout_entry() 9: 4ddb34209e = 9: e1b886f823 entry: add checkout_entry_ca() which takes preloaded conv_attrs 10: af0d790973 ! 10: 2bdc13664e unpack-trees: add basic support for parallel checkout @@ parallel-checkout.c (new) +} + +static int write_pc_item_to_fd(struct parallel_checkout_item *pc_item, int fd, -+ const char *path, struct checkout *state) ++ const char *path) +{ + int ret; + struct stream_filter *filter; @@ parallel-checkout.c (new) + goto out; + } + -+ if (write_pc_item_to_fd(pc_item, fd, path.buf, state)) { ++ if (write_pc_item_to_fd(pc_item, fd, path.buf)) { + /* Error was already reported. */ + pc_item->status = PC_ITEM_FAILED; + goto out; 11: 991169488b ! 11: 096e543fd2 parallel-checkout: make it truly parallel @@ Documentation/config/checkout.txt: will checkout the '<something>' branch on ano + The number of parallel workers to use when updating the working tree. + The default is one, i.e. sequential execution. If set to a value less + than one, Git will use as many workers as the number of logical cores -+ available. This setting and checkout.thresholdForParallelism affect all -+ commands that perform checkout. E.g. checkout, switch, clone, reset, -+ sparse-checkout, read-tree, etc. ++ available. This setting and `checkout.thresholdForParallelism` affect ++ all commands that perform checkout. E.g. checkout, clone, reset, ++ sparse-checkout, etc. ++ +Note: parallel checkout usually delivers better performance for repositories +located on SSDs or over NFS. For repositories on spinning disks and/or machines @@ parallel-checkout.c: static void write_pc_item(struct parallel_checkout_item *pc + + fixed_portion = (struct pc_item_fixed_portion *)data; + fixed_portion->id = pc_item->id; -+ oidcpy(&fixed_portion->oid, &pc_item->ce->oid); + fixed_portion->ce_mode = pc_item->ce->ce_mode; + fixed_portion->crlf_action = pc_item->ca.crlf_action; + fixed_portion->ident = pc_item->ca.ident; + fixed_portion->name_len = name_len; + fixed_portion->working_tree_encoding_len = working_tree_encoding_len; ++ /* ++ * We use hashcpy() instead of oidcpy() because the hash[] positions ++ * after `the_hash_algo->rawsz` might not be initialized. And Valgrind ++ * would complain about passing uninitialized bytes to a syscall ++ * (write(2)). There is no real harm in this case, but the warning could ++ * hinder the detection of actual errors. ++ */ ++ hashcpy(fixed_portion->oid.hash, pc_item->ce->oid.hash); + + variant = data + sizeof(*fixed_portion); + if (working_tree_encoding_len) { 12: 7ceadf2427 = 12: 9cfeb4821c parallel-checkout: support progress displaying 13: f13b4c17f4 = 13: da99b671e6 make_transient_cache_entry(): optionally alloc from mem_pool 14: d7885a1130 = 14: d3d561754a builtin/checkout.c: complete parallel checkout support 15: 1cf9b807f7 ! 15: ee34c6e149 checkout-index: add parallel checkout support @@ builtin/checkout-index.c #define CHECKOUT_ALL 4 static int nul_term_line; @@ builtin/checkout-index.c: int cmd_checkout_index(int argc, const char **argv, const char *prefix) - int prefix_length; int force = 0, quiet = 0, not_new = 0; int index_opt = 0; + int err = 0; + int pc_workers, pc_threshold; struct option builtin_checkout_index_options[] = { OPT_BOOL('a', "all", &all, @@ builtin/checkout-index.c: int cmd_checkout_index(int argc, const char **argv, co for (i = 0; i < argc; i++) { const char *arg = argv[i]; @@ builtin/checkout-index.c: int cmd_checkout_index(int argc, const char **argv, const char *prefix) + strbuf_release(&buf); + } + +- if (err) +- return 1; +- if (all) checkout_all(prefix, prefix_length); + if (pc_workers > 1) { -+ /* Errors were already reported */ -+ run_parallel_checkout(&state, pc_workers, pc_threshold, -+ NULL, NULL); ++ err |= run_parallel_checkout(&state, pc_workers, pc_threshold, ++ NULL, NULL); + } ++ ++ if (err) ++ return 1; + if (is_lock_file_locked(&lock_file) && write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) 16: 64b41d537e ! 16: 05299a3cc0 parallel-checkout: add tests for basic operations @@ Commit message for symlinks in the leading directories and the abidance to --force. Note: some helper functions are added to a common lib file which is only - included by t2080 for now. But it will also be used by another - parallel-checkout test in a following patch. + included by t2080 for now. But it will also be used by other + parallel-checkout tests in the following patches. Original-patch-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> Signed-off-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> @@ t/lib-parallel-checkout.sh (new) + +# Runs `git -c checkout.workers=$1 -c checkout.thesholdForParallelism=$2 ${@:4}` +# and checks that the number of workers spawned is equal to $3. ++# +git_pc() +{ + if test $# -lt 4 + then + BUG "too few arguments to git_pc()" -+ fi ++ fi && + + workers=$1 threshold=$2 expected_workers=$3 && -+ shift && shift && shift && ++ shift 3 && + + rm -f trace && + GIT_TRACE2="$(pwd)/trace" git \ + -c checkout.workers=$workers \ + -c checkout.thresholdForParallelism=$threshold \ + -c advice.detachedHead=0 \ -+ $@ && ++ "$@" && + + # Check that the expected number of workers has been used. Note that it -+ # can be different than the requested number in two cases: when the -+ # quantity of entries to be checked out is less than the number of -+ # workers; and when the threshold has not been reached. ++ # can be different from the requested number in two cases: when the ++ # threshold is not reached; and when there are not enough ++ # parallel-eligible entries for all workers. + # -+ local workers_in_trace=$(grep "child_start\[.\+\] git checkout--helper" trace | wc -l) && ++ local workers_in_trace=$(grep "child_start\[..*\] git checkout--helper" trace | wc -l) && + test $workers_in_trace -eq $expected_workers && + rm -f trace +} @@ t/lib-parallel-checkout.sh (new) +# Verify that both the working tree and the index were created correctly +verify_checkout() +{ -+ git -C $1 diff-index --quiet HEAD -- && -+ git -C $1 diff-index --quiet --cached HEAD -- && -+ git -C $1 status --porcelain >$1.status && -+ test_must_be_empty $1.status ++ git -C "$1" diff-index --quiet HEAD -- && ++ git -C "$1" diff-index --quiet --cached HEAD -- && ++ git -C "$1" status --porcelain >"$1".status && ++ test_must_be_empty "$1".status +} ## t/t2080-parallel-checkout-basics.sh (new) ## @@ t/t2080-parallel-checkout-basics.sh (new) +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-parallel-checkout.sh" + -+# NEEDSWORK: cloning a SHA1 repo with GIT_TEST_DEFAULT_HASH set to "sha256" -+# currently produces a wrong result (See -+# https://lore.kernel.org/git/20200911151717.43475-1-matheus.bernardino@xxxxxx/). -+# So we skip the "parallel-checkout during clone" tests when this test flag is -+# set to "sha256". Remove this when the bug is fixed. -+# -+if test "$GIT_TEST_DEFAULT_HASH" = "sha256" -+then -+ skip_all="t2080 currently don't work with GIT_TEST_DEFAULT_HASH=sha256" -+ test_done -+fi -+ -+R_BASE=$GIT_BUILD_DIR -+ -+test_expect_success 'sequential clone' ' -+ git_pc 1 0 0 clone --quiet -- $R_BASE r_sequential && -+ verify_checkout r_sequential -+' -+ -+test_expect_success 'parallel clone' ' -+ git_pc 2 0 2 clone --quiet -- $R_BASE r_parallel && -+ verify_checkout r_parallel -+' -+ -+test_expect_success 'fallback to sequential clone (threshold)' ' -+ git -C $R_BASE ls-files >files && -+ nr_files=$(wc -l <files) && -+ threshold=$(($nr_files + 1)) && -+ -+ git_pc 2 $threshold 0 clone --quiet -- $R_BASE r_sequential_fallback && -+ verify_checkout r_sequential_fallback -+' -+ -+# Just to be paranoid, actually compare the contents of the worktrees directly. -+test_expect_success 'compare working trees from clones' ' -+ rm -rf r_sequential/.git && -+ rm -rf r_parallel/.git && -+ rm -rf r_sequential_fallback/.git && -+ diff -qr r_sequential r_parallel && -+ diff -qr r_sequential r_sequential_fallback -+' -+ +# Test parallel-checkout with different operations (creation, deletion, +# modification) and entry types. A branch switch from B1 to B2 will contain: +# @@ t/t2080-parallel-checkout-basics.sh (new) + verify_checkout various_sequential_fallback +' + -+test_expect_success SYMLINKS 'compare working trees from checkouts' ' -+ rm -rf various_sequential/.git && -+ rm -rf various_parallel/.git && -+ rm -rf various_sequential_fallback/.git && -+ diff -qr various_sequential various_parallel && -+ diff -qr various_sequential various_sequential_fallback ++test_expect_success SYMLINKS 'parallel checkout on clone' ' ++ git -C various checkout --recurse-submodules B2 && ++ git_pc 2 0 2 clone --recurse-submodules various various_parallel_clone && ++ verify_checkout various_parallel_clone ++' ++ ++test_expect_success SYMLINKS 'fallback to sequential checkout on clone (threshold)' ' ++ git -C various checkout --recurse-submodules B2 && ++ git_pc 2 100 0 clone --recurse-submodules various various_sequential_fallback_clone && ++ verify_checkout various_sequential_fallback_clone ++' ++ ++# Just to be paranoid, actually compare the working trees' contents directly. ++test_expect_success SYMLINKS 'compare the working trees' ' ++ rm -rf various_*/.git && ++ rm -rf various_*/d/.git && ++ ++ diff -r various_sequential various_parallel && ++ diff -r various_sequential various_sequential_fallback && ++ diff -r various_sequential various_parallel_clone && ++ diff -r various_sequential various_sequential_fallback_clone +' + +test_cmp_str() 17: 70708d3e31 ! 17: 3d140dcacb parallel-checkout: add tests related to clone collisions @@ Commit message Signed-off-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> Signed-off-by: Matheus Tavares <matheus.bernardino@xxxxxx> + ## t/lib-parallel-checkout.sh ## +@@ t/lib-parallel-checkout.sh: git_pc() + -c checkout.workers=$workers \ + -c checkout.thresholdForParallelism=$threshold \ + -c advice.detachedHead=0 \ +- "$@" && ++ "$@" 2>&8 && + + # Check that the expected number of workers has been used. Note that it + # can be different from the requested number in two cases: when the +@@ t/lib-parallel-checkout.sh: git_pc() + local workers_in_trace=$(grep "child_start\[..*\] git checkout--helper" trace | wc -l) && + test $workers_in_trace -eq $expected_workers && + rm -f trace +-} ++} 8>&2 2>&4 + + # Verify that both the working tree and the index were created correctly + verify_checkout() + ## t/t2081-parallel-checkout-collisions.sh (new) ## @@ +#!/bin/sh + -+test_description='parallel-checkout collisions' ++test_description='parallel-checkout collisions ++ ++When there are path collisions during a clone, Git should report a warning ++listing all of the colliding entries. The sequential code detects a collision ++by calling lstat() before trying to open(O_CREAT) the file. Then, to find the ++colliding pair of an item k, it searches cache_entry[0, k-1]. ++ ++This is not sufficient in parallel checkout since: ++ ++- A colliding file may be created between the lstat() and open() calls; ++- A colliding entry might appear in the second half of the cache_entry array. ++ ++The tests in this file make sure that the collision detection code is extended ++for parallel checkout. ++' + +. ./test-lib.sh ++. "$TEST_DIRECTORY/lib-parallel-checkout.sh" + -+# When there are pathname collisions during a clone, Git should report a warning -+# listing all of the colliding entries. The sequential code detects a collision -+# by calling lstat() before trying to open(O_CREAT) the file. Then, to find the -+# colliding pair of an item k, it searches cache_entry[0, k-1]. -+# -+# This is not sufficient in parallel-checkout mode since colliding files may be -+# created in a racy order. The tests in this file make sure the collision -+# detection code is extended for parallel-checkout. This is done in two parts: -+# -+# - First, two parallel workers create four colliding files racily. -+# - Then this exercise is repeated but forcing the colliding pair to appear in -+# the second half of the cache_entry's array. -+# -+# The second item uses the fact that files with clean/smudge filters are not -+# parallel-eligible; and that they are processed sequentially *before* any -+# worker is spawned. We set a filter attribute to the last entry in the -+# cache_entry[] array, making it non-eligible, so that it is populated first. -+# This way, we can test if the collision detection code is correctly looking -+# for collision pairs in the second half of the array. ++TEST_ROOT="$PWD" + +test_expect_success CASE_INSENSITIVE_FS 'setup' ' -+ file_hex=$(git hash-object -w --stdin </dev/null) && -+ file_oct=$(echo $file_hex | hex2oct) && ++ file_x_hex=$(git hash-object -w --stdin </dev/null) && ++ file_x_oct=$(echo $file_x_hex | hex2oct) && + + attr_hex=$(echo "file_x filter=logger" | git hash-object -w --stdin) && + attr_oct=$(echo $attr_hex | hex2oct) && + -+ printf "100644 FILE_X\0${file_oct}" >tree && -+ printf "100644 FILE_x\0${file_oct}" >>tree && -+ printf "100644 file_X\0${file_oct}" >>tree && -+ printf "100644 file_x\0${file_oct}" >>tree && ++ printf "100644 FILE_X\0${file_x_oct}" >tree && ++ printf "100644 FILE_x\0${file_x_oct}" >>tree && ++ printf "100644 file_X\0${file_x_oct}" >>tree && ++ printf "100644 file_x\0${file_x_oct}" >>tree && + printf "100644 .gitattributes\0${attr_oct}" >>tree && + + tree_hex=$(git hash-object -w -t tree --stdin <tree) && + commit_hex=$(git commit-tree -m collisions $tree_hex) && + git update-ref refs/heads/collisions $commit_hex && + -+ write_script logger_script <<-\EOF ++ write_script "$TEST_ROOT"/logger_script <<-\EOF + echo "$@" >>filter.log + EOF +' + -+clone_and_check_collision() -+{ -+ id=$1 workers=$2 threshold=$3 expected_workers=$4 filter=$5 && -+ -+ filter_opts= -+ if test "$filter" -eq "use_filter" -+ then -+ # We use `core.ignoreCase=0` so that only `file_x` -+ # matches the pattern in .gitattributes. -+ # -+ filter_opts='-c filter.logger.smudge="../logger_script %f" -c core.ignoreCase=0' -+ fi && -+ -+ test_path_is_missing $id.trace && -+ GIT_TRACE2="$(pwd)/$id.trace" git \ -+ -c checkout.workers=$workers \ -+ -c checkout.thresholdForParallelism=$threshold \ -+ $filter_opts clone --branch=collisions -- . r_$id 2>$id.warning && -+ -+ # Check that checkout spawned the right number of workers -+ workers_in_trace=$(grep "child_start\[.\] git checkout--helper" $id.trace | wc -l) && -+ test $workers_in_trace -eq $expected_workers && -+ -+ if test $filter -eq "use_filter" -+ then -+ # Make sure only 'file_x' was filtered -+ test_path_is_file r_$id/filter.log && ++for mode in parallel sequential-fallback ++do ++ ++ case $mode in ++ parallel) workers=2 threshold=0 expected_workers=2 ;; ++ sequential-fallback) workers=2 threshold=100 expected_workers=0 ;; ++ esac ++ ++ test_expect_success CASE_INSENSITIVE_FS "collision detection on $mode clone" ' ++ git_pc $workers $threshold $expected_workers \ ++ clone --branch=collisions . $mode 2>$mode.stderr && ++ ++ grep FILE_X $mode.stderr && ++ grep FILE_x $mode.stderr && ++ grep file_X $mode.stderr && ++ grep file_x $mode.stderr && ++ test_i18ngrep "the following paths have collided" $mode.stderr ++ ' ++ ++ # The following test ensures that the collision detection code is ++ # correctly looking for colliding peers in the second half of the ++ # cache_entry array. This is done by defining a smudge command for the ++ # *last* array entry, which makes it non-eligible for parallel-checkout. ++ # The last entry is then checked out *before* any worker is spawned, ++ # making it succeed and the workers' entries collide. ++ # ++ # Note: this test don't work on Windows because, on this system, ++ # collision detection uses strcmp() when core.ignoreCase=false. And we ++ # have to set core.ignoreCase=false so that only 'file_x' matches the ++ # pattern of the filter attribute. But it works on OSX, where collision ++ # detection uses inode. ++ # ++ test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN "collision detection on $mode clone w/ filter" ' ++ git_pc $workers $threshold $expected_workers \ ++ -c core.ignoreCase=false \ ++ -c filter.logger.smudge="\"$TEST_ROOT/logger_script\" %f" \ ++ clone --branch=collisions . ${mode}_with_filter \ ++ 2>${mode}_with_filter.stderr && ++ ++ grep FILE_X ${mode}_with_filter.stderr && ++ grep FILE_x ${mode}_with_filter.stderr && ++ grep file_X ${mode}_with_filter.stderr && ++ grep file_x ${mode}_with_filter.stderr && ++ test_i18ngrep "the following paths have collided" ${mode}_with_filter.stderr && ++ ++ # Make sure only "file_x" was filtered ++ test_path_is_file ${mode}_with_filter/filter.log && + echo file_x >expected.filter.log && -+ test_cmp r_$id/filter.log expected.filter.log -+ else -+ test_path_is_missing r_$id/filter.log -+ fi && -+ -+ grep FILE_X $id.warning && -+ grep FILE_x $id.warning && -+ grep file_X $id.warning && -+ grep file_x $id.warning && -+ test_i18ngrep "the following paths have collided" $id.warning -+} -+ -+test_expect_success CASE_INSENSITIVE_FS 'collision detection on parallel clone' ' -+ clone_and_check_collision parallel 2 0 2 -+' -+ -+test_expect_success CASE_INSENSITIVE_FS 'collision detection on fallback to sequential clone' ' -+ git ls-tree --name-only -r collisions >files && -+ nr_files=$(wc -l <files) && -+ threshold=$(($nr_files + 1)) && -+ clone_and_check_collision sequential 2 $threshold 0 -+' -+ -+# The next two tests don't work on Windows because, on this system, collision -+# detection uses strcmp() (when core.ignoreCase=0) to find the colliding pair. -+# But they work on OSX, where collision detection uses inode. -+ -+test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN 'collision detection on parallel clone w/ filter' ' -+ clone_and_check_collision parallel-with-filter 2 0 2 use_filter -+' -+ -+test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN 'collision detection on fallback to sequential clone w/ filter' ' -+ git ls-tree --name-only -r collisions >files && -+ nr_files=$(wc -l <files) && -+ threshold=$(($nr_files + 1)) && -+ clone_and_check_collision sequential-with-filter 2 $threshold 0 use_filter -+' ++ test_cmp ${mode}_with_filter/filter.log expected.filter.log ++ ' ++done + +test_done 18: ece38f0483 = 18: b26f676cae parallel-checkout: add tests related to .gitattributes 19: b4cb5905d2 ! 19: 641c61f9b6 ci: run test round with parallel-checkout enabled @@ t/lib-parallel-checkout.sh + # Runs `git -c checkout.workers=$1 -c checkout.thesholdForParallelism=$2 ${@:4}` # and checks that the number of workers spawned is equal to $3. - git_pc() - - ## t/t2081-parallel-checkout-collisions.sh ## -@@ - test_description='parallel-checkout collisions' - - . ./test-lib.sh -+. "$TEST_DIRECTORY/lib-parallel-checkout.sh" - - # When there are pathname collisions during a clone, Git should report a warning - # listing all of the colliding entries. The sequential code detects a collision + # -- 2.28.0