]> git.ipfire.org Git - thirdparty/git.git/commitdiff
subtree: allow 'split' flags to be passed to 'push'
authorLuke Shumaker <lukeshu@datawire.io>
Tue, 27 Apr 2021 21:17:46 +0000 (15:17 -0600)
committerJunio C Hamano <gitster@pobox.com>
Wed, 28 Apr 2021 07:47:19 +0000 (16:47 +0900)
'push' does a 'split' internally, but it doesn't pass flags through to the
'split'.  This is silly, if you need to pass flags to 'split', then it
means that you can't use 'push'!

So, have 'push' accept 'split' flags, and pass them through to 'split'.

Add tests for this by copying split's tests with minimal modification.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
contrib/subtree/git-subtree.sh
contrib/subtree/git-subtree.txt
contrib/subtree/t/t7900-subtree.sh

index 25d69d7973447ac022677670737cce3b42342c20..431214a1d336ac9de5af010d0150fecbd1392b4e 100755 (executable)
@@ -33,13 +33,13 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
- options for 'split'
+ options for 'split' (also: 'push')
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
+ options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
 squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
@@ -964,7 +964,7 @@ cmd_push () {
                repository=$1
                refspec=$2
                echo "git push using: " "$repository" "$refspec"
-               localrev=$(git subtree split --prefix="$arg_prefix") || die
+               localrev=$(cmd_split) || die
                git push "$repository" "$localrev":"refs/heads/$refspec"
        else
                die "'$dir' must already exist. Try 'git subtree add'."
index d7e6e7867c2d4e7b4fe1719ed01b961ca54713ee..fbb52f127badc6ca866f407699b4fcc6beb4f3c1 100644 (file)
@@ -137,11 +137,11 @@ OPTIONS FOR ALL COMMANDS
        want to manipulate.  This option is mandatory
        for all commands.
 
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
------------------------------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull', 'split --rejoin', AND 'push --rejoin')
+-----------------------------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
-'merge' as appropriate).
+wraps 'merge'), 'split --rejoin' (which wraps either 'add' or 'merge'
+as appropriate), and 'push --rejoin' (which wraps 'split --rejoin').
 
 --squash::
        Instead of merging the entire history from the subtree project, produce
@@ -173,9 +173,10 @@ subproject.
 --message=<message>::
        Specify <message> as the commit message for the merge commit.
 
-OPTIONS FOR 'split'
--------------------
-These options are only valid for 'split'.
+OPTIONS FOR 'split' (ALSO: 'push')
+----------------------------------
+These options for 'split' may also be given to 'push' (which wraps
+'split').
 
 --annotate=<annotation>::
        When generating synthetic history, add <annotation> as a prefix to each
index 2561e25f439875559dbe1367e08ce1d9fb886daa..5a6541437b7c222cbcfc1dfc20467152ebe99ef0 100755 (executable)
@@ -5,8 +5,8 @@
 #
 test_description='Basic porcelain support for subtrees
 
-This test verifies the basic operation of the add, pull, merge
-and split subcommands of git subtree.
+This test verifies the basic operation of the add, merge, split, pull,
+and push subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
@@ -610,6 +610,216 @@ test_expect_success 'push basic operation' '
        )
 '
 
+test_expect_success 'push sub dir/ with --rejoin' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+               git subtree push --prefix="sub dir" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+               test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+               test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push sub dir/ with --rejoin from scratch' '
+       subtree_test_create_repo "$test_count" &&
+       test_create_commit "$test_count" main1 &&
+       (
+               cd "$test_count" &&
+               mkdir "sub dir" &&
+               echo file >"sub dir"/file &&
+               git add "sub dir/file" &&
+               git commit -m"sub dir file" &&
+               split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
+               git init --bare "sub proj.git" &&
+               git subtree push --prefix="sub dir" --rejoin ./"sub proj.git" from-mainline &&
+               test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+               test "$split_hash" = "$(git -C "sub proj.git" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push sub dir/ with --rejoin and --message' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               git subtree push --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+               test "$(last_commit_subject)" = "Split & rejoin" &&
+               split_hash="$(git rev-parse --verify HEAD^2)" &&
+               test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push "sub dir"/ with --rejoin and --squash' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" --squash FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+               MAIN=$(git rev-parse --verify HEAD) &&
+               SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+               SPLIT=$(git subtree split --prefix="sub dir" --annotate="*") &&
+               git subtree push --prefix="sub dir" --annotate="*" --rejoin --squash ./"sub proj" from-mainline &&
+
+               test_must_fail git merge-base --is-ancestor $SUB HEAD &&
+               test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
+               git rev-list HEAD ^$MAIN >commit-list &&
+               test_line_count = 2 commit-list &&
+               test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+               test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+               test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+               test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+               test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+               test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''" &&
+               test "$SPLIT" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push "sub dir"/ with --branch' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+               git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+               test "$(git rev-parse subproj-br)" = "$split_hash" &&
+               test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'check hash of push' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+               git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+               test "$(git rev-parse subproj-br)" = "$split_hash" &&
+               # Check hash of split
+               new_hash=$(git rev-parse subproj-br^2) &&
+               (
+                       cd ./"sub proj" &&
+                       subdir_hash=$(git rev-parse HEAD) &&
+                       test "$new_hash" = "$subdir_hash"
+               ) &&
+               test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an existing branch' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git branch subproj-br FETCH_HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+               git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+               test "$(git rev-parse subproj-br)" = "$split_hash" &&
+               test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+       )
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
+       subtree_test_create_repo "$test_count" &&
+       subtree_test_create_repo "$test_count/sub proj" &&
+       test_create_commit "$test_count" main1 &&
+       test_create_commit "$test_count/sub proj" sub1 &&
+       (
+               cd "$test_count" &&
+               git branch init HEAD &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree add --prefix="sub dir" FETCH_HEAD
+       ) &&
+       test_create_commit "$test_count" "sub dir"/main-sub1 &&
+       test_create_commit "$test_count" main2 &&
+       test_create_commit "$test_count/sub proj" sub2 &&
+       test_create_commit "$test_count" "sub dir"/main-sub2 &&
+       (
+               cd "$test_count" &&
+               git fetch ./"sub proj" HEAD &&
+               git subtree merge --prefix="sub dir" FETCH_HEAD &&
+               test_must_fail git subtree push --prefix="sub dir" --branch init "./sub proj" from-mainline
+       )
+'
+
 #
 # Validity checking
 #