diff options
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/buildsystems/CMakeLists.txt | 38 | ||||
| -rw-r--r-- | contrib/completion/git-completion.bash | 149 | ||||
| -rw-r--r-- | contrib/completion/git-prompt.sh | 31 | ||||
| -rw-r--r-- | contrib/credential/wincred/git-credential-wincred.c | 46 | ||||
| -rwxr-xr-x | contrib/subtree/git-subtree.sh | 64 | ||||
| -rwxr-xr-x | contrib/subtree/t/t7900-subtree.sh | 40 |
6 files changed, 329 insertions, 39 deletions
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 6b819e2fbd..804629c525 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -974,6 +974,35 @@ target_link_libraries(test-fake-ssh common-main) parse_makefile_for_sources(test-reftable_SOURCES "REFTABLE_TEST_OBJS") list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") +#unit-tests +add_library(unit-test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c) + +parse_makefile_for_scripts(unit_test_PROGRAMS "UNIT_TEST_PROGRAMS" "") +foreach(unit_test ${unit_test_PROGRAMS}) + add_executable("${unit_test}" "${CMAKE_SOURCE_DIR}/t/unit-tests/${unit_test}.c") + target_link_libraries("${unit_test}" unit-test-lib common-main) + set_target_properties("${unit_test}" + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin) + if(MSVC) + set_target_properties("${unit_test}" + PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin) + set_target_properties("${unit_test}" + PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin) + endif() + list(APPEND PROGRAMS_BUILT "${unit_test}") + + # t-basic intentionally fails tests, to validate the unit-test infrastructure. + # Therefore, it should only be run as part of t0080, which verifies that it + # fails only in the expected ways. + # + # All other unit tests should be run. + if(NOT ${unit_test} STREQUAL "t-basic") + add_test(NAME "t.unit-tests.${unit_test}" + COMMAND "./${unit_test}" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t/unit-tests/bin) + endif() +endforeach() + #test-tool parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS") @@ -1093,17 +1122,18 @@ if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH}) file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/) endif() -file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh") +file(GLOB test_scripts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh") #test -foreach(tsh ${test_scipts}) - add_test(NAME ${tsh} +foreach(tsh ${test_scripts}) + string(REGEX REPLACE ".*/(.*)\\.sh" "\\1" test_name ${tsh}) + add_test(NAME "t.suite.${test_name}" COMMAND ${SH_EXE} ${tsh} --no-bin-wrappers --no-chain-lint -vx WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t) endforeach() # This test script takes an extremely long time and is known to time out even # on fast machines because it requires in excess of one hour to run -set_tests_properties("${CMAKE_SOURCE_DIR}/t/t7112-reset-submodule.sh" PROPERTIES TIMEOUT 4000) +set_tests_properties("t.suite.t7112-reset-submodule" PROPERTIES TIMEOUT 4000) endif()#BUILD_TESTING diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e21a39b406..c3408d4143 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -137,6 +137,9 @@ __git_eread () __git_pseudoref_exists () { local ref=$1 + local head + + __git_find_repo_path # If the reftable is in use, we have to shell out to 'git rev-parse' # to determine whether the ref exists instead of looking directly in @@ -144,9 +147,8 @@ __git_pseudoref_exists () # Bash builtins since executing Git commands are expensive on some # platforms. if __git_eread "$__git_repo_path/HEAD" head; then - b="${head#ref: }" - if [ "$b" == "refs/heads/.invalid" ]; then - __git -C "$__git_repo_path" rev-parse --verify --quiet "$ref" 2>/dev/null + if [ "$head" == "ref: refs/heads/.invalid" ]; then + __git show-ref --exists "$ref" return $? fi fi @@ -1656,7 +1658,6 @@ __git_cherry_pick_inprogress_options=$__git_sequencer_inprogress_options _git_cherry_pick () { - __git_find_repo_path if __git_pseudoref_exists CHERRY_PICK_HEAD; then __gitcomp "$__git_cherry_pick_inprogress_options" return @@ -1807,7 +1808,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --output= --output-indicator-context= --output-indicator-new= --output-indicator-old= --ws-error-highlight= - --pickaxe-all --pickaxe-regex + --pickaxe-all --pickaxe-regex --patch-with-raw " # Options for diff/difftool @@ -2071,6 +2072,16 @@ __git_log_common_options=" --min-age= --until= --before= --min-parents= --max-parents= --no-min-parents --no-max-parents + --alternate-refs --ancestry-path + --author-date-order --basic-regexp + --bisect --boundary --exclude-first-parent-only + --exclude-hidden --extended-regexp + --fixed-strings --grep-reflog + --ignore-missing --left-only --perl-regexp + --reflog --regexp-ignore-case --remove-empty + --right-only --show-linear-break + --show-notes-by-default --show-pulls + --since-as-filter --single-worktree " # Options that go well for log and gitk (not shortlog) __git_log_gitk_options=" @@ -2086,6 +2097,7 @@ __git_log_shortlog_options=" # Options accepted by log and show __git_log_show_options=" --diff-merges --diff-merges= --no-diff-merges --dd --remerge-diff + --encoding= " __git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r" @@ -2169,6 +2181,8 @@ _git_log () --no-walk --no-walk= --do-walk --parents --children --expand-tabs --expand-tabs= --no-expand-tabs + --clear-decorations --decorate-refs= + --decorate-refs-exclude= $merge $__git_diff_common_options " @@ -2966,7 +2980,6 @@ _git_reset () _git_restore () { - __git_find_repo_path case "$prev" in -s) __git_complete_refs @@ -2995,7 +3008,6 @@ __git_revert_inprogress_options=$__git_sequencer_inprogress_options _git_revert () { - __git_find_repo_path if __git_pseudoref_exists REVERT_HEAD; then __gitcomp "$__git_revert_inprogress_options" return @@ -3117,12 +3129,119 @@ __gitcomp_directories () COMPREPLY+=("$c/") _found=1 fi - done < <(git ls-tree -z -d --name-only HEAD $_tmp_dir) + done < <(__git ls-tree -z -d --name-only HEAD $_tmp_dir) if [[ $_found == 0 ]] && [[ "$cur" =~ /$ ]]; then # No possible further completions any deeper, so assume we're at # a leaf directory and just consider it complete __gitcomp_direct_append "$cur " + elif [[ $_found == 0 ]]; then + # No possible completions found. Avoid falling back to + # bash's default file and directory completion, because all + # valid completions have already been searched and the + # fallbacks can do nothing but mislead. In fact, they can + # mislead in three different ways: + # 1) Fallback file completion makes no sense when asking + # for directory completions, as this function does. + # 2) Fallback directory completion is bad because + # e.g. "/pro" is invalid and should NOT complete to + # "/proc". + # 3) Fallback file/directory completion only completes + # on paths that exist in the current working tree, + # i.e. which are *already* part of their + # sparse-checkout. Thus, normal file and directory + # completion is always useless for "git + # sparse-checkout add" and is also probelmatic for + # "git sparse-checkout set" unless using it to + # strictly narrow the checkout. + COMPREPLY=( "" ) + fi +} + +# In non-cone mode, the arguments to {set,add} are supposed to be +# patterns, relative to the toplevel directory. These can be any kind +# of general pattern, like 'subdir/*.c' and we can't complete on all +# of those. However, if the user presses Tab to get tab completion, we +# presume that they are trying to provide a pattern that names a specific +# path. +__gitcomp_slash_leading_paths () +{ + local dequoted_word pfx="" cur_ toplevel + + # Since we are dealing with a sparse-checkout, subdirectories may not + # exist in the local working copy. Therefore, we want to run all + # ls-files commands relative to the repository toplevel. + toplevel="$(git rev-parse --show-toplevel)/" + + __git_dequote "$cur" + + # If the paths provided by the user already start with '/', then + # they are considered relative to the toplevel of the repository + # already. If they do not start with /, then we need to adjust + # them to start with the appropriate prefix. + case "$cur" in + /*) + cur="${cur:1}" + ;; + *) + pfx="$(__git rev-parse --show-prefix)" + esac + + # Since sparse-index is limited to cone-mode, in non-cone-mode the + # list of valid paths is precisely the cached files in the index. + # + # NEEDSWORK: + # 1) We probably need to take care of cases where ls-files + # responds with special quoting. + # 2) We probably need to take care of cases where ${cur} has + # some kind of special quoting. + # 3) On top of any quoting from 1 & 2, we have to provide an extra + # level of quoting for any paths that contain a '*', '?', '\', + # '[', ']', or leading '#' or '!' since those will be + # interpreted by sparse-checkout as something other than a + # literal path character. + # Since there are two types of quoting here, this might get really + # complex. For now, just punt on all of this... + completions="$(__git -C "${toplevel}" -c core.quotePath=false \ + ls-files --cached -- "${pfx}${cur}*" \ + | sed -e s%^%/% -e 's%$% %')" + # Note, above, though that we needed all of the completions to be + # prefixed with a '/', and we want to add a space so that bash + # completion will actually complete an entry and let us move on to + # the next one. + + # Return what we've found. + if test -n "$completions"; then + # We found some completions; return them + local IFS=$'\n' + COMPREPLY=($completions) + else + # Do NOT fall back to bash-style all-local-files-and-dirs + # when we find no match. Such options are worse than + # useless: + # 1. "git sparse-checkout add" needs paths that are NOT + # currently in the working copy. "git + # sparse-checkout set" does as well, except in the + # special cases when users are only trying to narrow + # their sparse checkout to a subset of what they + # already have. + # + # 2. A path like '.config' is ambiguous as to whether + # the user wants all '.config' files throughout the + # tree, or just the one under the current directory. + # It would result in a warning from the + # sparse-checkout command due to this. As such, all + # completions of paths should be prefixed with a + # '/'. + # + # 3. We don't want paths prefixed with a '/' to + # complete files in the system root directory, we + # want it to complete on files relative to the + # repository root. + # + # As such, make sure that NO completions are offered rather + # than falling back to bash's default completions. + COMPREPLY=( "" ) fi } @@ -3130,6 +3249,7 @@ _git_sparse_checkout () { local subcommands="list init set disable add reapply" local subcommand="$(__git_find_on_cmdline "$subcommands")" + local using_cone=true if [ -z "$subcommand" ]; then __gitcomp "$subcommands" return @@ -3140,9 +3260,18 @@ _git_sparse_checkout () __gitcomp_builtin sparse-checkout_$subcommand "" "--" ;; set,*|add,*) - if [ "$(__git config core.sparseCheckoutCone)" == "true" ] || - [ -n "$(__git_find_on_cmdline --cone)" ]; then + if [[ "$(__git config core.sparseCheckout)" == "true" && + "$(__git config core.sparseCheckoutCone)" == "false" && + -z "$(__git_find_on_cmdline --cone)" ]]; then + using_cone=false + fi + if [[ -n "$(__git_find_on_cmdline --no-cone)" ]]; then + using_cone=false + fi + if [[ "$using_cone" == "true" ]]; then __gitcomp_directories + else + __gitcomp_slash_leading_paths fi esac } diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 2c030050ae..71f179cba3 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -408,7 +408,7 @@ __git_ps1 () local repo_info rev_parse_exit_code repo_info="$(git rev-parse --git-dir --is-inside-git-dir \ - --is-bare-repository --is-inside-work-tree \ + --is-bare-repository --is-inside-work-tree --show-ref-format \ --short HEAD 2>/dev/null)" rev_parse_exit_code="$?" @@ -421,6 +421,8 @@ __git_ps1 () short_sha="${repo_info##*$'\n'}" repo_info="${repo_info%$'\n'*}" fi + local ref_format="${repo_info##*$'\n'}" + repo_info="${repo_info%$'\n'*}" local inside_worktree="${repo_info##*$'\n'}" repo_info="${repo_info%$'\n'*}" local bare_repo="${repo_info##*$'\n'}" @@ -479,12 +481,25 @@ __git_ps1 () b="$(git symbolic-ref HEAD 2>/dev/null)" else local head="" - if ! __git_eread "$g/HEAD" head; then - return $exit - fi - # is it a symbolic ref? - b="${head#ref: }" - if [ "$head" = "$b" ]; then + + case "$ref_format" in + files) + if ! __git_eread "$g/HEAD" head; then + return $exit + fi + + if [[ $head == "ref: "* ]]; then + head="${head#ref: }" + else + head="" + fi + ;; + *) + head="$(git symbolic-ref HEAD 2>/dev/null)" + ;; + esac + + if test -z "$head"; then detached=yes b="$( case "${GIT_PS1_DESCRIBE_STYLE-}" in @@ -502,6 +517,8 @@ __git_ps1 () b="$short_sha..." b="($b)" + else + b="$head" fi fi fi diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c index 4cd56c42e2..4be0d58cd8 100644 --- a/contrib/credential/wincred/git-credential-wincred.c +++ b/contrib/credential/wincred/git-credential-wincred.c @@ -35,7 +35,7 @@ static void *xmalloc(size_t size) } static WCHAR *wusername, *password, *protocol, *host, *path, target[1024], - *password_expiry_utc; + *password_expiry_utc, *oauth_refresh_token; static void write_item(const char *what, LPCWSTR wbuf, int wlen) { @@ -140,6 +140,11 @@ static void get_credential(void) DWORD num_creds; int i; CREDENTIAL_ATTRIBUTEW *attr; + WCHAR *secret; + WCHAR *line; + WCHAR *remaining_lines; + WCHAR *part; + WCHAR *remaining_parts; if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds)) return; @@ -149,9 +154,24 @@ static void get_credential(void) if (match_cred(creds[i], 0)) { write_item("username", creds[i]->UserName, creds[i]->UserName ? wcslen(creds[i]->UserName) : 0); - write_item("password", - (LPCWSTR)creds[i]->CredentialBlob, - creds[i]->CredentialBlobSize / sizeof(WCHAR)); + if (creds[i]->CredentialBlobSize > 0) { + secret = xmalloc(creds[i]->CredentialBlobSize); + wcsncpy_s(secret, creds[i]->CredentialBlobSize, (LPCWSTR)creds[i]->CredentialBlob, creds[i]->CredentialBlobSize / sizeof(WCHAR)); + line = wcstok_s(secret, L"\r\n", &remaining_lines); + write_item("password", line, line ? wcslen(line) : 0); + while(line != NULL) { + part = wcstok_s(line, L"=", &remaining_parts); + if (!wcscmp(part, L"oauth_refresh_token")) { + write_item("oauth_refresh_token", remaining_parts, remaining_parts ? wcslen(remaining_parts) : 0); + } + line = wcstok_s(NULL, L"\r\n", &remaining_lines); + } + free(secret); + } else { + write_item("password", + (LPCWSTR)creds[i]->CredentialBlob, + creds[i]->CredentialBlobSize / sizeof(WCHAR)); + } for (int j = 0; j < creds[i]->AttributeCount; j++) { attr = creds[i]->Attributes + j; if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) { @@ -170,16 +190,26 @@ static void store_credential(void) { CREDENTIALW cred; CREDENTIAL_ATTRIBUTEW expiry_attr; + WCHAR *secret; + int wlen; if (!wusername || !password) return; + if (oauth_refresh_token) { + wlen = _scwprintf(L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token); + secret = xmalloc(sizeof(WCHAR) * wlen); + _snwprintf_s(secret, sizeof(WCHAR) * wlen, wlen, L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token); + } else { + secret = _wcsdup(password); + } + cred.Flags = 0; cred.Type = CRED_TYPE_GENERIC; cred.TargetName = target; cred.Comment = L"saved by git-credential-wincred"; - cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR); - cred.CredentialBlob = (LPVOID)password; + cred.CredentialBlobSize = wcslen(secret) * sizeof(WCHAR); + cred.CredentialBlob = (LPVOID)_wcsdup(secret); cred.Persist = CRED_PERSIST_LOCAL_MACHINE; cred.AttributeCount = 0; cred.Attributes = NULL; @@ -194,6 +224,8 @@ static void store_credential(void) cred.TargetAlias = NULL; cred.UserName = wusername; + free(secret); + if (!CredWriteW(&cred, 0)) die("CredWrite failed"); } @@ -265,6 +297,8 @@ static void read_credential(void) password = utf8_to_utf16_dup(v); else if (!strcmp(buf, "password_expiry_utc")) password_expiry_utc = utf8_to_utf16_dup(v); + else if (!strcmp(buf, "oauth_refresh_token")) + oauth_refresh_token = utf8_to_utf16_dup(v); /* * Ignore other lines; we don't know what they mean, but * this future-proofs us when later versions of git do diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index e0c5d3b0de..5dab3f506c 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -373,7 +373,8 @@ try_remove_previous () { # Usage: process_subtree_split_trailer SPLIT_HASH MAIN_HASH [REPOSITORY] process_subtree_split_trailer () { - assert test $# = 2 -o $# = 3 + assert test $# -ge 2 + assert test $# -le 3 b="$1" sq="$2" repository="" @@ -402,7 +403,8 @@ process_subtree_split_trailer () { # Usage: find_latest_squash DIR [REPOSITORY] find_latest_squash () { - assert test $# = 1 -o $# = 2 + assert test $# -ge 1 + assert test $# -le 2 dir="$1" repository="" if test "$#" = 2 @@ -455,7 +457,8 @@ find_latest_squash () { # Usage: find_existing_splits DIR REV [REPOSITORY] find_existing_splits () { - assert test $# = 2 -o $# = 3 + assert test $# -ge 2 + assert test $# -le 3 debug "Looking for prior splits..." local indent=$(($indent + 1)) @@ -489,13 +492,13 @@ find_existing_splits () { ;; END) debug "Main is: '$main'" - if test -z "$main" -a -n "$sub" + if test -z "$main" && test -n "$sub" then # squash commits refer to a subtree debug " Squash: $sq from $sub" cache_set "$sq" "$sub" fi - if test -n "$main" -a -n "$sub" + if test -n "$main" && test -n "$sub" then debug " Prior: $main -> $sub" cache_set $main $sub @@ -638,10 +641,16 @@ subtree_for_commit () { while read mode type tree name do assert test "$name" = "$dir" - assert test "$type" = "tree" -o "$type" = "commit" - test "$type" = "commit" && continue # ignore submodules - echo $tree - break + + case "$type" in + commit) + continue;; # ignore submodules + tree) + echo $tree + break;; + *) + die "fatal: tree entry is of type ${type}, expected tree or commit";; + esac done || exit $? } @@ -778,6 +787,22 @@ ensure_valid_ref_format () { die "fatal: '$1' does not look like a ref" } +# Usage: check if a commit from another subtree should be +# ignored from processing for splits +should_ignore_subtree_split_commit () { + assert test $# = 1 + local rev="$1" + if test -n "$(git log -1 --grep="git-subtree-dir:" $rev)" + then + if test -z "$(git log -1 --grep="git-subtree-mainline:" $rev)" && + test -z "$(git log -1 --grep="git-subtree-dir: $arg_prefix$" $rev)" + then + return 0 + fi + fi + return 1 +} + # Usage: process_split_commit REV PARENTS process_split_commit () { assert test $# = 2 @@ -916,7 +941,7 @@ cmd_split () { if test $# -eq 0 then rev=$(git rev-parse HEAD) - elif test $# -eq 1 -o $# -eq 2 + elif test $# -eq 1 || test $# -eq 2 then rev=$(git rev-parse -q --verify "$1^{commit}") || die "fatal: '$1' does not refer to a commit" @@ -963,7 +988,19 @@ cmd_split () { eval "$grl" | while read rev parents do - process_split_commit "$rev" "$parents" + if should_ignore_subtree_split_commit "$rev" + then + continue + fi + parsedparents='' + for parent in $parents + do + if ! should_ignore_subtree_split_commit "$parent" + then + parsedparents="$parsedparents$parent " + fi + done + process_split_commit "$rev" "$parsedparents" done || exit $? latest_new=$(cache_get latest_new) || exit $? @@ -1006,8 +1043,11 @@ cmd_split () { # Usage: cmd_merge REV [REPOSITORY] cmd_merge () { - test $# -eq 1 -o $# -eq 2 || + if test $# -lt 1 || test $# -gt 2 + then die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'" + fi + rev=$(git rev-parse -q --verify "$1^{commit}") || die "fatal: '$1' does not refer to a commit" repository="" diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 49a21dd7c9..ca4df5be83 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -385,6 +385,46 @@ test_expect_success 'split sub dir/ with --rejoin' ' ) ' +# Tests that commits from other subtrees are not processed as +# part of a split. +# +# This test performs the following: +# - Creates Repo with subtrees 'subA' and 'subB' +# - Creates commits in the repo including changes to subtrees +# - Runs the following 'split' and commit' commands in order: +# - Perform 'split' on subtree A +# - Perform 'split' on subtree B +# - Create new commits with changes to subtree A and B +# - Perform split on subtree A +# - Check that the commits in subtree B are not processed +# as part of the subtree A split +test_expect_success 'split with multiple subtrees' ' + subtree_test_create_repo "$test_count" && + subtree_test_create_repo "$test_count/subA" && + subtree_test_create_repo "$test_count/subB" && + test_create_commit "$test_count" main1 && + test_create_commit "$test_count/subA" subA1 && + test_create_commit "$test_count/subA" subA2 && + test_create_commit "$test_count/subA" subA3 && + test_create_commit "$test_count/subB" subB1 && + git -C "$test_count" fetch ./subA HEAD && + git -C "$test_count" subtree add --prefix=subADir FETCH_HEAD && + git -C "$test_count" fetch ./subB HEAD && + git -C "$test_count" subtree add --prefix=subBDir FETCH_HEAD && + test_create_commit "$test_count" subADir/main-subA1 && + test_create_commit "$test_count" subBDir/main-subB1 && + git -C "$test_count" subtree split --prefix=subADir \ + --squash --rejoin -m "Sub A Split 1" && + git -C "$test_count" subtree split --prefix=subBDir \ + --squash --rejoin -m "Sub B Split 1" && + test_create_commit "$test_count" subADir/main-subA2 && + test_create_commit "$test_count" subBDir/main-subB2 && + git -C "$test_count" subtree split --prefix=subADir \ + --squash --rejoin -m "Sub A Split 2" && + test "$(git -C "$test_count" subtree split --prefix=subBDir \ + --squash --rejoin -d -m "Sub B Split 1" 2>&1 | grep -w "\[1\]")" = "" +' + test_expect_success 'split sub dir/ with --rejoin from scratch' ' subtree_test_create_repo "$test_count" && test_create_commit "$test_count" main1 && |
