subtree: push: allow specifying a local rev other than HEAD

'git subtree split' lets you specify a rev other than HEAD. 'git push' lets you specify a mapping between a local thing and a remot ref. So smash those together, and have 'git subtree push' let you specify which local thing to run split on and push the result of that split to the remote ref. Signed-off-by: Luke Shumaker <lukeshu@datawire.io> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Luke Shumaker committed Apr 27, 2021 at 15:17 UTC 49470cd445166fbe778218c7618ea8ee78ca7d00
3 files changed +47 -13
contrib/subtree/git-subtree.sh
+17 -7
@@ -27,7 +27,7 @@ git subtree add --prefix=<prefix> <repository> <ref>
27 git subtree merge --prefix=<prefix> <commit>
28 git subtree split --prefix=<prefix> [<commit>]
29 git subtree pull --prefix=<prefix> <repository> <ref>
30 -git subtree push --prefix=<prefix> <repository> <ref>
30 +git subtree push --prefix=<prefix> <repository> <refspec>
31 --
32 h,help show the help
33 q quiet
@@ -952,20 +952,30 @@ cmd_pull () {
952 cmd_merge FETCH_HEAD
953 }
954
955 -# Usage: cmd_push REPOSITORY REMOTEREF
955 +# Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF
956 cmd_push () {
957 if test $# -ne 2
958 then
959 - die "You must provide <repository> <ref>"
959 + die "You must provide <repository> <refspec>"
960 fi
961 - ensure_valid_ref_format "$2"
961 if test -e "$dir"
962 then
963 repository=$1
965 - refspec=$2
964 + refspec=${2#+}
965 + remoteref=${refspec#*:}
966 + if test "$remoteref" = "$refspec"
967 + then
968 + localrevname_presplit=HEAD
969 + else
970 + localrevname_presplit=${refspec%%:*}
971 + fi
972 + ensure_valid_ref_format "$remoteref"
973 + localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") ||
974 + die "'$localrevname_presplit' does not refer to a commit"
975 +
976 echo "git push using: " "$repository" "$refspec"
967 - localrev=$(cmd_split) || die
968 - git push "$repository" "$localrev":"refs/heads/$refspec"
977 + localrev=$(cmd_split "$localrev_presplit") || die
978 + git push "$repository" "$localrev":"refs/heads/$remoteref"
979 else
980 die "'$dir' must already exist. Try 'git subtree add'."
981 fi
contrib/subtree/git-subtree.txt
+8 -6
@@ -16,7 +16,7 @@ SYNOPSIS
16
17 [verse]
18 'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
19 -'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
19 +'git subtree' [<options>] -P <prefix> push <repository> <refspec>
20
21 DESCRIPTION
22 -----------
@@ -115,11 +115,13 @@ pull <repository> <remote-ref>::
115 it fetches the given ref from the specified remote
116 repository.
117
118 -push <repository> <remote-ref>::
119 - Does a 'split' using the <prefix> subtree of HEAD and then
120 - does a 'git push' to push the result to the <repository> and
121 - <remote-ref>. This can be used to push your subtree to
122 - different branches of the remote repository.
118 +push <repository> [+][<local-commit>:]<remote-ref>::
119 + Does a 'split' using the <prefix> subtree of <local-commit>
120 + and then does a 'git push' to push the result to the
121 + <repository> and <remote-ref>. This can be used to push your
122 + subtree to different branches of the remote repository. Just
123 + as with 'split', if no <local-commit> is given, then HEAD is
124 + used. The optional leading '+' is ignored.
125
126 OPTIONS FOR ALL COMMANDS
127 ------------------------
contrib/subtree/t/t7900-subtree.sh
+22
@@ -820,6 +820,28 @@ test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
820 )
821 '
822
823 +test_expect_success 'push "sub dir"/ with a local rev' '
824 + subtree_test_create_repo "$test_count" &&
825 + subtree_test_create_repo "$test_count/sub proj" &&
826 + test_create_commit "$test_count" main1 &&
827 + test_create_commit "$test_count/sub proj" sub1 &&
828 + (
829 + cd "$test_count" &&
830 + git fetch ./"sub proj" HEAD &&
831 + git subtree add --prefix="sub dir" FETCH_HEAD
832 + ) &&
833 + test_create_commit "$test_count" "sub dir"/main-sub1 &&
834 + test_create_commit "$test_count" "sub dir"/main-sub2 &&
835 + (
836 + cd "$test_count" &&
837 + bad_tree=$(git rev-parse --verify HEAD:"sub dir") &&
838 + good_tree=$(git rev-parse --verify HEAD^:"sub dir") &&
839 + git subtree push --prefix="sub dir" --annotate="*" ./"sub proj" HEAD^:from-mainline &&
840 + split_tree=$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline:) &&
841 + test "$split_tree" = "$good_tree"
842 + )
843 +'
844 +
845 #
846 # Validity checking
847 #