Git fork

Merge branch 'cs/subtree-squash-split-fix'

"git subtree" (in contrib/) did not work correctly when splitting
squashed subtrees, which has been improved.

* cs/subtree-squash-split-fix:
contrib/subtree: fix split with squashed subtrees

+99 -8
+28 -8
contrib/subtree/git-subtree.sh
··· 785 785 die "fatal: '$1' does not look like a ref" 786 786 } 787 787 788 - # Usage: check if a commit from another subtree should be 788 + # Usage: should_ignore_subtree_split_commit REV 789 + # 790 + # Check if REV is a commit from another subtree and should be 789 791 # ignored from processing for splits 790 792 should_ignore_subtree_split_commit () { 791 793 assert test $# = 1 792 - local rev="$1" 793 - if test -n "$(git log -1 --grep="git-subtree-dir:" $rev)" 794 + 795 + git show \ 796 + --no-patch \ 797 + --no-show-signature \ 798 + --format='%(trailers:key=git-subtree-dir,key=git-subtree-mainline)' \ 799 + "$1" | 800 + ( 801 + have_mainline= 802 + subtree_dir= 803 + 804 + while read -r trailer val 805 + do 806 + case "$trailer" in 807 + git-subtree-dir:) 808 + subtree_dir="${val%/}" ;; 809 + git-subtree-mainline:) 810 + have_mainline=y ;; 811 + esac 812 + done 813 + 814 + if test -n "${subtree_dir}" && 815 + test -z "${have_mainline}" && 816 + test "${subtree_dir}" != "$arg_prefix" 794 817 then 795 - if test -z "$(git log -1 --grep="git-subtree-mainline:" $rev)" && 796 - test -z "$(git log -1 --grep="git-subtree-dir: $arg_prefix$" $rev)" 797 - then 798 - return 0 799 - fi 818 + return 0 800 819 fi 801 820 return 1 821 + ) 802 822 } 803 823 804 824 # Usage: process_split_commit REV PARENTS
+71
contrib/subtree/t/t7900-subtree.sh
··· 9 9 and push subcommands of git subtree. 10 10 ' 11 11 12 + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 13 + export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 14 + 12 15 TEST_DIRECTORY=$(pwd)/../../../t 13 16 . "$TEST_DIRECTORY"/test-lib.sh 14 17 . "$TEST_DIRECTORY"/lib-gpg.sh ··· 66 69 git clone --no-local "$1" "$1-clone" && 67 70 new_commit=$(sed -e "s/$commit/$tag/" msg | git -C "$1-clone" commit-tree HEAD^2^{tree}) && 68 71 git -C "$1-clone" replace HEAD^2 $new_commit 72 + } 73 + 74 + # test_create_subtree_add REPO ORPHAN PREFIX FILENAME ... 75 + # 76 + # Create a simple subtree on a new branch named ORPHAN in REPO. 77 + # The subtree is then merged into the current branch of REPO, 78 + # under PREFIX. The generated subtree has has one commit 79 + # with subject and tag FILENAME with a single file "FILENAME.t" 80 + # 81 + # When this method returns: 82 + # - the current branch of REPO will have file PREFIX/FILENAME.t 83 + # - REPO will have a branch named ORPHAN with subtree history 84 + # 85 + # additional arguments are forwarded to "subtree add" 86 + test_create_subtree_add () { 87 + ( 88 + cd "$1" && 89 + orphan="$2" && 90 + prefix="$3" && 91 + filename="$4" && 92 + shift 4 && 93 + last="$(git branch --show-current)" && 94 + git switch --orphan "$orphan" && 95 + test_commit "$filename" && 96 + git checkout "$last" && 97 + git subtree add --prefix="$prefix" "$@" "$orphan" 98 + ) 69 99 } 70 100 71 101 test_expect_success 'shows short help text for -h' ' ··· 425 455 test "$(git -C "$test_count" subtree split --prefix=subBDir \ 426 456 --squash --rejoin -d -m "Sub B Split 1" 2>&1 | grep -w "\[1\]")" = "" 427 457 ' 458 + 459 + # When subtree split-ing a directory that has other subtree 460 + # *merges* underneath it, the split must include those subtrees. 461 + # This test creates a nested subtree, `subA/subB`, and tests 462 + # that the tree is correct after a subtree split of `subA/`. 463 + # The test covers: 464 + # - An initial `subtree add`; and 465 + # - A follow-up `subtree merge` 466 + # both with and without `--squashed`. 467 + for is_squashed in '' 'y' 468 + do 469 + test_expect_success "split keeps nested ${is_squashed:+--squash }subtrees that are part of the split" ' 470 + subtree_test_create_repo "$test_count" && 471 + ( 472 + cd "$test_count" && 473 + mkdir subA && 474 + test_commit subA/file1 && 475 + test_create_subtree_add \ 476 + . mksubtree subA/subB file2 ${is_squashed:+--squash} && 477 + test_path_is_file subA/file1.t && 478 + test_path_is_file subA/subB/file2.t && 479 + git subtree split --prefix=subA --branch=bsplit && 480 + git checkout bsplit && 481 + test_path_is_file file1.t && 482 + test_path_is_file subB/file2.t && 483 + git checkout mksubtree && 484 + git branch -D bsplit && 485 + test_commit file3 && 486 + git checkout main && 487 + git subtree merge \ 488 + ${is_squashed:+--squash} \ 489 + --prefix=subA/subB mksubtree && 490 + test_path_is_file subA/subB/file3.t && 491 + git subtree split --prefix=subA --branch=bsplit && 492 + git checkout bsplit && 493 + test_path_is_file file1.t && 494 + test_path_is_file subB/file2.t && 495 + test_path_is_file subB/file3.t 496 + ) 497 + ' 498 + done 428 499 429 500 test_expect_success 'split sub dir/ with --rejoin from scratch' ' 430 501 subtree_test_create_repo "$test_count" &&