Skip to content

Commit cb65514

Browse files
LukeShugitster
authored andcommitted
subtree: allow --squash to be used with --rejoin
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6468784 commit cb65514

File tree

3 files changed

+96
-24
lines changed

3 files changed

+96
-24
lines changed

contrib/subtree/git-subtree.sh

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ h,help show the help
3333
q quiet
3434
d show debug messages
3535
P,prefix= the name of the subdir to split out
36-
m,message= use the given message as the commit message for the merge commit
3736
options for 'split'
3837
annotate= add a prefix to commit message of new commits
3938
b,branch= create a new branch from the split subtree
4039
ignore-joins ignore prior --rejoin commits
4140
onto= try connecting new tree to an existing one
4241
rejoin merge the new branch back into HEAD
43-
options for 'add' and 'merge' (also: 'pull')
42+
options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
4443
squash merge subtree changes as a single commit
44+
m,message= use the given message as the commit message for the merge commit
4545
"
4646

4747
arg_debug=
@@ -346,7 +346,8 @@ find_latest_squash () {
346346
then
347347
# a rejoin commit?
348348
# Pretend its sub was a squash.
349-
sq="$sub"
349+
sq=$(git rev-parse --verify "$sq^2") ||
350+
die
350351
fi
351352
debug "Squash found: $sq $sub"
352353
echo "$sq" "$sub"
@@ -453,6 +454,13 @@ add_msg () {
453454
else
454455
commit_message="Add '$dir/' from commit '$latest_new'"
455456
fi
457+
if test -n "$arg_split_rejoin"
458+
then
459+
# If this is from a --rejoin, then rejoin_msg has
460+
# already inserted the `git-subtree-xxx:` tags
461+
echo "$commit_message"
462+
return
463+
fi
456464
cat <<-EOF
457465
$commit_message
458466
@@ -775,7 +783,12 @@ cmd_add_commit () {
775783
rev=$(git rev-parse --verify "$1^{commit}") || exit $?
776784

777785
debug "Adding $dir as '$rev'..."
778-
git read-tree --prefix="$dir" $rev || exit $?
786+
if test -z "$arg_split_rejoin"
787+
then
788+
# Only bother doing this if this is a genuine 'add',
789+
# not a synthetic 'add' from '--rejoin'.
790+
git read-tree --prefix="$dir" $rev || exit $?
791+
fi
779792
git checkout -- "$dir" || exit $?
780793
tree=$(git write-tree) || exit $?
781794

@@ -815,6 +828,11 @@ cmd_split () {
815828
die "You must provide exactly one revision. Got: '$*'"
816829
fi
817830

831+
if test -n "$arg_split_rejoin"
832+
then
833+
ensure_clean
834+
fi
835+
818836
debug "Splitting $dir..."
819837
cache_setup || exit $?
820838

@@ -857,10 +875,13 @@ cmd_split () {
857875
then
858876
debug "Merging split branch into HEAD..."
859877
latest_old=$(cache_get latest_old) || exit $?
860-
git merge -s ours \
861-
--allow-unrelated-histories \
862-
-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
863-
"$latest_new" >&2 || exit $?
878+
arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?
879+
if test -z "$(find_latest_squash "$dir")"
880+
then
881+
cmd_add "$latest_new" >&2 || exit $?
882+
else
883+
cmd_merge "$latest_new" >&2 || exit $?
884+
fi
864885
fi
865886
if test -n "$arg_split_branch"
866887
then

contrib/subtree/git-subtree.txt

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,6 @@ settings passed to 'split' (such as '--annotate') are the same.
109109
Because of this, if you add new commits and then re-split, the new
110110
commits will be attached as commits on top of the history you
111111
generated last time, so 'git merge' and friends will work as expected.
112-
+
113-
Note that if you use '--squash' when you merge, you should usually not
114-
just '--rejoin' when you split.
115112

116113
pull <repository> <remote-ref>::
117114
Exactly like 'merge', but parallels 'git pull' in that
@@ -124,8 +121,8 @@ push <repository> <remote-ref>::
124121
<remote-ref>. This can be used to push your subtree to
125122
different branches of the remote repository.
126123

127-
OPTIONS
128-
-------
124+
OPTIONS FOR ALL COMMANDS
125+
------------------------
129126
-q::
130127
--quiet::
131128
Suppress unnecessary output messages on stderr.
@@ -140,15 +137,11 @@ OPTIONS
140137
want to manipulate. This option is mandatory
141138
for all commands.
142139

143-
-m <message>::
144-
--message=<message>::
145-
This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
146-
Specify <message> as the commit message for the merge commit.
147-
148-
OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
149-
--------------------------------------------
140+
OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
141+
-----------------------------------------------------------------
150142
These options for 'add' and 'merge' may also be given to 'pull' (which
151-
wraps 'merge').
143+
wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
144+
'merge' as appropriate).
152145

153146
--squash::
154147
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
176169
remain intact and can be later split and send upstream to the
177170
subproject.
178171

172+
-m <message>::
173+
--message=<message>::
174+
Specify <message> as the commit message for the merge commit.
179175

180176
OPTIONS FOR 'split'
181177
-------------------
@@ -229,9 +225,8 @@ Unfortunately, using this option results in 'git log' showing an extra
229225
copy of every new commit that was created (the original, and the
230226
synthetic one).
231227
+
232-
If you do all your merges with '--squash', don't use '--rejoin' when you
233-
split, because you don't want the subproject's history to be part of
234-
your project anyway.
228+
If you do all your merges with '--squash', make sure you also use
229+
'--squash' when you 'split --rejoin'.
235230

236231

237232
EXAMPLE 1. 'add' command

contrib/subtree/t/t7900-subtree.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,62 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
324324
)
325325
'
326326

327+
test_expect_success 'split "sub dir"/ with --rejoin and --squash' '
328+
subtree_test_create_repo "$test_count" &&
329+
subtree_test_create_repo "$test_count/sub proj" &&
330+
test_create_commit "$test_count" main1 &&
331+
test_create_commit "$test_count/sub proj" sub1 &&
332+
(
333+
cd "$test_count" &&
334+
git fetch ./"sub proj" HEAD &&
335+
git subtree add --prefix="sub dir" --squash FETCH_HEAD
336+
) &&
337+
test_create_commit "$test_count" "sub dir"/main-sub1 &&
338+
test_create_commit "$test_count" main2 &&
339+
test_create_commit "$test_count/sub proj" sub2 &&
340+
test_create_commit "$test_count" "sub dir"/main-sub2 &&
341+
(
342+
cd "$test_count" &&
343+
git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
344+
MAIN=$(git rev-parse --verify HEAD) &&
345+
SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
346+
347+
SPLIT=$(git subtree split --prefix="sub dir" --annotate="*" --rejoin --squash) &&
348+
349+
test_must_fail git merge-base --is-ancestor $SUB HEAD &&
350+
test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
351+
git rev-list HEAD ^$MAIN >commit-list &&
352+
test_line_count = 2 commit-list &&
353+
test "$(git rev-parse --verify HEAD:)" = "$(git rev-parse --verify $MAIN:)" &&
354+
test "$(git rev-parse --verify HEAD:"sub dir")" = "$(git rev-parse --verify $SPLIT:)" &&
355+
test "$(git rev-parse --verify HEAD^1)" = $MAIN &&
356+
test "$(git rev-parse --verify HEAD^2)" != $SPLIT &&
357+
test "$(git rev-parse --verify HEAD^2:)" = "$(git rev-parse --verify $SPLIT:)" &&
358+
test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''"
359+
)
360+
'
361+
362+
test_expect_success 'split then pull "sub dir"/ with --rejoin and --squash' '
363+
# 1. "add"
364+
subtree_test_create_repo "$test_count" &&
365+
subtree_test_create_repo "$test_count/sub proj" &&
366+
test_create_commit "$test_count" main1 &&
367+
test_create_commit "$test_count/sub proj" sub1 &&
368+
git -C "$test_count" subtree --prefix="sub dir" add --squash ./"sub proj" HEAD &&
369+
370+
# 2. commit from parent
371+
test_create_commit "$test_count" "sub dir"/main-sub1 &&
372+
373+
# 3. "split --rejoin --squash"
374+
git -C "$test_count" subtree --prefix="sub dir" split --rejoin --squash &&
375+
376+
# 4. "pull --squash"
377+
test_create_commit "$test_count/sub proj" sub2 &&
378+
git -C "$test_count" subtree -d --prefix="sub dir" pull --squash ./"sub proj" HEAD &&
379+
380+
test_must_fail git merge-base HEAD FETCH_HEAD
381+
'
382+
327383
test_expect_success 'split "sub dir"/ with --branch' '
328384
subtree_test_create_repo "$test_count" &&
329385
subtree_test_create_repo "$test_count/sub proj" &&

0 commit comments

Comments
 (0)