Besides being a genuinely useful thing to do, this also just makes sense
and harmonizes which flags may be used when. `git subtree split
--rejoin` amounts to "automatically go ahead and do a `git subtree
merge` after doing the main `git subtree split`", so it's weird and
arbitrary that you can't pass `--squash` to `git subtree split --rejoin`
like you can `git subtree merge`. It's weird that `git subtree split
--rejoin` inherits `git subtree merge`'s `--message` but not `--squash`.
Reconcile the situation by just having `split --rejoin` actually just
call `merge` internally (or call `add` instead, as appropriate), so it
can get access to the full `merge` behavior, including `--squash`.
Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Luke Shumaker committedApr 27, 2021 at 15:17 UTCcb6551447b8e0c35408b766ad605ba357f720a0d
3 files changed+96-21
contrib/subtree/git-subtree.sh
+29-8
index 3bffddf277..25d69d7973 100755--- a/contrib/subtree/git-subtree.sh+++ b/contrib/subtree/git-subtree.sh@@ -33,15 +33,15 @@ h,help show the help q quiet d show debug messages P,prefix= the name of the subdir to split out-m,message= use the given message as the commit message for the merge commit options for 'split' 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')+ options for 'add' and 'merge' (also: 'pull' and 'split --rejoin') squash merge subtree changes as a single commit+m,message= use the given message as the commit message for the merge commit " arg_debug=@@ -346,7 +346,8 @@ find_latest_squash () { then # a rejoin commit? # Pretend its sub was a squash.- sq="$sub"+ sq=$(git rev-parse --verify "$sq^2") ||+ die fi debug "Squash found: $sq $sub" echo "$sq" "$sub"@@ -453,6 +454,13 @@ add_msg () { else commit_message="Add '$dir/' from commit '$latest_new'" fi+ if test -n "$arg_split_rejoin"+ then+ # If this is from a --rejoin, then rejoin_msg has+ # already inserted the `git-subtree-xxx:` tags+ echo "$commit_message"+ return+ fi cat <<-EOF $commit_message@@ -775,7 +783,12 @@ cmd_add_commit () { rev=$(git rev-parse --verify "$1^{commit}") || exit $? debug "Adding $dir as '$rev'..."- git read-tree --prefix="$dir" $rev || exit $?+ if test -z "$arg_split_rejoin"+ then+ # Only bother doing this if this is a genuine 'add',+ # not a synthetic 'add' from '--rejoin'.+ git read-tree --prefix="$dir" $rev || exit $?+ fi git checkout -- "$dir" || exit $? tree=$(git write-tree) || exit $?@@ -815,6 +828,11 @@ cmd_split () { die "You must provide exactly one revision. Got: '$*'" fi+ if test -n "$arg_split_rejoin"+ then+ ensure_clean+ fi+ debug "Splitting $dir..." cache_setup || exit $?@@ -857,10 +875,13 @@ cmd_split () { then debug "Merging split branch into HEAD..." latest_old=$(cache_get latest_old) || exit $?- git merge -s ours \- --allow-unrelated-histories \- -m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \- "$latest_new" >&2 || exit $?+ arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?+ if test -z "$(find_latest_squash "$dir")"+ then+ cmd_add "$latest_new" >&2 || exit $?+ else+ cmd_merge "$latest_new" >&2 || exit $?+ fi fi if test -n "$arg_split_branch" then
contrib/subtree/git-subtree.txt
+11-13
index 78baac1e6b..d7e6e7867c 100644--- a/contrib/subtree/git-subtree.txt+++ b/contrib/subtree/git-subtree.txt@@ -109,9 +109,6 @@ settings passed to 'split' (such as '--annotate') are the same. Because of this, if you add new commits and then re-split, the new commits will be attached as commits on top of the history you generated last time, so 'git merge' and friends will work as expected.-+-Note that if you use '--squash' when you merge, you should usually not-just '--rejoin' when you split. pull <repository> <remote-ref>:: Exactly like 'merge', but parallels 'git pull' in that@@ -124,8 +121,8 @@ push <repository> <remote-ref>:: <remote-ref>. This can be used to push your subtree to different branches of the remote repository.-OPTIONS--------+OPTIONS FOR ALL COMMANDS+------------------------ -q:: --quiet:: Suppress unnecessary output messages on stderr.@@ -140,15 +137,11 @@ OPTIONS want to manipulate. This option is mandatory for all commands.--m <message>::---message=<message>::- This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.- Specify <message> as the commit message for the merge commit.--OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')---------------------------------------------+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')+----------------------------------------------------------------- These options for 'add' and 'merge' may also be given to 'pull' (which-wraps 'merge').+wraps 'merge') and 'split --rejoin' (which wraps either 'add' or+'merge' as appropriate). --squash:: Instead of merging the entire history from the subtree project, produce@@ -176,6 +169,9 @@ Whether or not you use '--squash', changes made in your local repository remain intact and can be later split and send upstream to the subproject.+-m <message>::+--message=<message>::+ Specify <message> as the commit message for the merge commit. OPTIONS FOR 'split' -------------------@@ -229,9 +225,8 @@ Unfortunately, using this option results in 'git log' showing an extra copy of every new commit that was created (the original, and the synthetic one). +-If you do all your merges with '--squash', don't use '--rejoin' when you-split, because you don't want the subproject's history to be part of-your project anyway.+If you do all your merges with '--squash', make sure you also use+'--squash' when you 'split --rejoin'. EXAMPLE 1. 'add' command