diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 9e4d9a0619..b06782bc79 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -44,17 +44,6 @@ squash merge subtree changes as a single commit m,message= use the given message as the commit message for the merge commit " -arg_debug= -arg_command= -arg_prefix= -arg_split_branch= -arg_split_onto= -arg_split_rejoin= -arg_split_ignore_joins= -arg_split_annotate= -arg_addmerge_squash= -arg_addmerge_message= - indent=0 # Usage: debug [MSG...] @@ -106,10 +95,61 @@ main () { then set -- -h fi - eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" + set_args="$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" + eval "$set_args" . git-sh-setup require_work_tree + # First figure out the command and whether we use --rejoin, so + # that we can provide more helpful validation when we do the + # "real" flag parsing. + arg_split_rejoin= + allow_split= + allow_addmerge= + while test $# -gt 0 + do + opt="$1" + shift + case "$opt" in + --annotate|-b|-P|-m|--onto) + shift + ;; + --rejoin) + arg_split_rejoin=1 + ;; + --no-rejoin) + arg_split_rejoin= + ;; + --) + break + ;; + esac + done + arg_command=$1 + case "$arg_command" in + add|merge|pull) + allow_addmerge=1 + ;; + split|push) + allow_split=1 + allow_addmerge=$arg_split_rejoin + ;; + *) + die "Unknown command '$arg_command'" + ;; + esac + # Reset the arguments array for "real" flag parsing. + eval "$set_args" + + # Begin "real" flag parsing. + arg_debug= + arg_prefix= + arg_split_branch= + arg_split_onto= + arg_split_ignore_joins= + arg_split_annotate= + arg_addmerge_squash= + arg_addmerge_message= while test $# -gt 0 do opt="$1" @@ -123,13 +163,16 @@ main () { arg_debug=1 ;; --annotate) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_annotate="$1" shift ;; --no-annotate) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_annotate= ;; -b) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_branch="$1" shift ;; @@ -138,6 +181,7 @@ main () { shift ;; -m) + test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_addmerge_message="$1" shift ;; @@ -145,28 +189,34 @@ main () { arg_prefix= ;; --onto) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_onto="$1" shift ;; --no-onto) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_onto= ;; --rejoin) - arg_split_rejoin=1 + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." ;; --no-rejoin) - arg_split_rejoin= + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." ;; --ignore-joins) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_ignore_joins=1 ;; --no-ignore-joins) + test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_split_ignore_joins= ;; --squash) + test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_addmerge_squash=1 ;; --no-squash) + test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'." arg_addmerge_squash= ;; --) @@ -177,19 +227,8 @@ main () { ;; esac done - - arg_command="$1" shift - case "$arg_command" in - add|merge|pull|split|push) - : - ;; - *) - die "Unknown command '$arg_command'" - ;; - esac - if test -z "$arg_prefix" then die "You must provide the --prefix option." diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index d7ad6ffff0..4153b65321 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -33,6 +33,12 @@ test_create_commit () ( git commit -m "$commit" || error "Could not commit" ) +test_wrong_flag() { + test_must_fail "$@" >out 2>err && + test_must_be_empty out && + grep "flag does not make sense with" err +} + last_commit_subject () { git log --pretty=format:%s -1 } @@ -72,6 +78,22 @@ test_expect_success 'no pull from non-existent subtree' ' ) ' +test_expect_success 'add rejects flags for split' ' + 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 && + test_wrong_flag git subtree add --prefix="sub dir" --annotate=foo FETCH_HEAD && + test_wrong_flag git subtree add --prefix="sub dir" --branch=foo FETCH_HEAD && + test_wrong_flag git subtree add --prefix="sub dir" --ignore-joins FETCH_HEAD && + test_wrong_flag git subtree add --prefix="sub dir" --onto=foo FETCH_HEAD && + test_wrong_flag git subtree add --prefix="sub dir" --rejoin FETCH_HEAD + ) +' + test_expect_success 'add subproj as subtree into sub dir/ with --prefix' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/sub proj" && @@ -128,6 +150,28 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr # Tests for 'git subtree merge' # +test_expect_success 'merge rejects flags for split' ' + 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 proj" sub2 && + ( + cd "$test_count" && + git fetch ./"sub proj" HEAD && + test_wrong_flag git subtree merge --prefix="sub dir" --annotate=foo FETCH_HEAD && + test_wrong_flag git subtree merge --prefix="sub dir" --branch=foo FETCH_HEAD && + test_wrong_flag git subtree merge --prefix="sub dir" --ignore-joins FETCH_HEAD && + test_wrong_flag git subtree merge --prefix="sub dir" --onto=foo FETCH_HEAD && + test_wrong_flag git subtree merge --prefix="sub dir" --rejoin FETCH_HEAD + ) +' + test_expect_success 'merge new subproj history into sub dir/ with --prefix' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/sub proj" && @@ -262,6 +306,30 @@ test_expect_success 'split requires path given by option --prefix must exist' ' ) ' +test_expect_success 'split rejects flags for add' ' + 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="*") && + test_wrong_flag git subtree split --prefix="sub dir" --squash && + test_wrong_flag git subtree split --prefix="sub dir" --message=foo + ) +' + test_expect_success 'split sub dir/ with --rejoin' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/sub proj" && @@ -542,6 +610,26 @@ test_expect_success 'pull basic operation' ' ) ' +test_expect_success 'pull rejects flags for split' ' + 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 proj" sub2 && + ( + test_must_fail git subtree pull --prefix="sub dir" --annotate=foo ./"sub proj" HEAD && + test_must_fail git subtree pull --prefix="sub dir" --branch=foo ./"sub proj" HEAD && + test_must_fail git subtree pull --prefix="sub dir" --ignore-joins ./"sub proj" HEAD && + test_must_fail git subtree pull --prefix="sub dir" --onto=foo ./"sub proj" HEAD && + test_must_fail git subtree pull --prefix="sub dir" --rejoin ./"sub proj" HEAD + ) +' + # # Tests for 'git subtree push' # @@ -584,6 +672,29 @@ test_expect_success 'push requires path given by option --prefix must exist' ' ) ' +test_expect_success 'push rejects flags for add' ' + 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 && + test_wrong_flag git subtree split --prefix="sub dir" --squash ./"sub proj" from-mainline && + test_wrong_flag git subtree split --prefix="sub dir" --message=foo ./"sub proj" from-mainline + ) +' + test_expect_success 'push basic operation' ' subtree_test_create_repo "$test_count" && subtree_test_create_repo "$test_count/sub proj" &&