contrib/subtree: Add tests for subtree add
[git] / contrib / subtree / t / t7900-subtree.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2012 Avery Pennaraum
4 # Copyright (c) 2015 Alexey Shumkin
5 #
6 test_description='Basic porcelain support for subtrees
7
8 This test verifies the basic operation of the add, pull, merge
9 and split subcommands of git subtree.
10 '
11
12 TEST_DIRECTORY=$(pwd)/../../../t
13 export TEST_DIRECTORY
14
15 . ../../../t/test-lib.sh
16
17 create()
18 {
19         echo "$1" >"$1"
20         git add "$1"
21 }
22
23 check_equal()
24 {
25         test_debug 'echo'
26         test_debug "echo \"check a:\" \"{$1}\""
27         test_debug "echo \"      b:\" \"{$2}\""
28         if [ "$1" = "$2" ]; then
29                 return 0
30         else
31                 return 1
32         fi
33 }
34
35 undo()
36 {
37         git reset --hard HEAD~
38 }
39
40 # Make sure no patch changes more than one file.
41 # The original set of commits changed only one file each.
42 # A multi-file change would imply that we pruned commits
43 # too aggressively.
44 join_commits()
45 {
46         commit=
47         all=
48         while read x y; do
49                 if [ -z "$x" ]; then
50                         continue
51                 elif [ "$x" = "commit:" ]; then
52                         if [ -n "$commit" ]; then
53                                 echo "$commit $all"
54                                 all=
55                         fi
56                         commit="$y"
57                 else
58                         all="$all $y"
59                 fi
60         done
61         echo "$commit $all"
62 }
63
64 last_commit_message()
65 {
66         git log --pretty=format:%s -1
67 }
68
69 test_expect_success 'init subproj' '
70         test_create_repo "sub proj"
71 '
72
73 # To the subproject!
74 cd ./"sub proj"
75
76 test_expect_success 'add sub1' '
77         create sub1 &&
78         git commit -m "sub1" &&
79         git branch sub1 &&
80         git branch -m master subproj
81 '
82
83 # Save this hash for testing later.
84
85 subdir_hash=$(git rev-parse HEAD)
86
87 test_expect_success 'add sub2' '
88         create sub2 &&
89         git commit -m "sub2" &&
90         git branch sub2
91 '
92
93 test_expect_success 'add sub3' '
94         create sub3 &&
95         git commit -m "sub3" &&
96         git branch sub3
97 '
98
99 # Back to mainline
100 cd ..
101
102 test_expect_success 'enable log.date=relative to catch errors' '
103         git config log.date relative
104 '
105
106 test_expect_success 'add main4' '
107         create main4 &&
108         git commit -m "main4" &&
109         git branch -m master mainline &&
110         git branch subdir
111 '
112
113 test_expect_success 'fetch subproj history' '
114         git fetch ./"sub proj" sub1 &&
115         git branch sub1 FETCH_HEAD
116 '
117
118 test_expect_success 'no subtree exists in main tree' '
119         test_must_fail git subtree merge --prefix="sub dir" sub1
120 '
121
122 test_expect_success 'no pull from non-existant subtree' '
123         test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" sub1
124 '
125
126 test_expect_success 'no merge from non-existent subtree' '
127         test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
128 '
129
130 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
131         git subtree add --prefix="sub dir" sub1 &&
132         check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse sub1)'\''" &&
133         undo
134 '
135
136 test_expect_success 'check if --message works for add' '
137         git subtree add --prefix="sub dir" --message="Added subproject" sub1 &&
138         check_equal ''"$(last_commit_message)"'' "Added subproject" &&
139         undo
140 '
141
142 test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --message' '
143         git subtree add --prefix="sub dir" --message="Added subproject" sub1 &&
144         check_equal "$(last_commit_message)" "Added subproject" &&
145         undo
146 '
147
148 test_expect_success 'check if --message works as -m and --prefix as -P' '
149         git subtree add -P "sub dir" -m "Added subproject using git subtree" sub1 &&
150         check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
151         undo
152 '
153
154 test_expect_success 'check if --message works with squash too' '
155         git subtree add -P "sub dir" -m "Added subproject with squash" --squash sub1 &&
156         check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
157         undo
158 '
159
160 test_expect_success 'add subproj as subtree into sub dir/ with --squash and --prefix and --message' '
161         git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash sub1 &&
162         check_equal "$(last_commit_message)" "Added subproject with squash" &&
163         undo
164 '
165
166 # Maybe delete
167 test_expect_success 'add subproj to mainline' '
168         git subtree add --prefix="sub dir"/ FETCH_HEAD &&
169         check_equal ''"$(last_commit_message)"'' "Add '"'sub dir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
170 '
171
172 test_expect_success 'merge the added subproj again, should do nothing' '
173         # this shouldn not actually do anything, since FETCH_HEAD
174         # is already a parent
175         result=$(git merge -s ours -m "merge -s -ours" FETCH_HEAD) &&
176         check_equal "${result}" "Already up-to-date."
177 '
178
179 test_expect_success 'add main-sub5' '
180         create "sub dir/main-sub5" &&
181         git commit -m "main-sub5"
182 '
183
184 test_expect_success 'add main6' '
185         create main6 &&
186         git commit -m "main6 boring"
187 '
188
189 test_expect_success 'add main-sub7' '
190         create "sub dir/main-sub7" &&
191         git commit -m "main-sub7"
192 '
193
194 test_expect_success 'fetch new subproj history' '
195         git fetch ./"sub proj" sub2 &&
196         git branch sub2 FETCH_HEAD
197 '
198
199 test_expect_success 'check if --message works for merge' '
200         git subtree merge --prefix="sub dir" -m "Merged changes from subproject" sub2 &&
201         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
202         undo
203 '
204
205 test_expect_success 'check if --message for merge works with squash too' '
206         git subtree merge --prefix "sub dir" -m "Merged changes from subproject using squash" --squash sub2 &&
207         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
208         undo
209 '
210
211 test_expect_success 'merge new subproj history into subdir' '
212         git subtree merge --prefix="sub dir" FETCH_HEAD &&
213         git branch pre-split &&
214         check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" &&
215         undo
216 '
217
218 test_expect_success 'split requires option --prefix' '
219         echo "You must provide the --prefix option." > expected &&
220         test_must_fail git subtree split > actual 2>&1 &&
221         test_debug "printf '"'"'expected: '"'"'" &&
222         test_debug "cat expected" &&
223         test_debug "printf '"'"'actual: '"'"'" &&
224         test_debug "cat actual" &&
225         test_cmp expected actual &&
226         rm -f expected actual
227 '
228
229 test_expect_success 'split requires path given by option --prefix must exist' '
230         echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
231         test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
232         test_debug "printf '"'"'expected: '"'"'" &&
233         test_debug "cat expected" &&
234         test_debug "printf '"'"'actual: '"'"'" &&
235         test_debug "cat actual" &&
236         test_cmp expected actual &&
237         rm -f expected actual
238 '
239
240 test_expect_success 'check if --message works for split+rejoin' '
241         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
242         git branch spl1 "$spl1" &&
243         check_equal ''"$(last_commit_message)"'' "Split & rejoin" &&
244         undo
245 '
246
247 test_expect_success 'check split with --branch' '
248         spl1=$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin) &&
249         undo &&
250         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr1 &&
251         check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
252 '
253
254 test_expect_success 'check hash of split' '
255         spl1=$(git subtree split --prefix "sub dir") &&
256         git subtree split --prefix "sub dir" --branch splitbr1test &&
257         check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1" &&
258         new_hash=$(git rev-parse splitbr1test~2) &&
259         check_equal ''"$new_hash"'' "$subdir_hash"
260 '
261
262 test_expect_success 'check split with --branch for an existing branch' '
263         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
264         undo &&
265         git branch splitbr2 sub1 &&
266         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr2 &&
267         check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
268 '
269
270 test_expect_success 'check split with --branch for an incompatible branch' '
271         test_must_fail git subtree split --prefix "sub dir" --onto FETCH_HEAD --branch subdir
272 '
273
274 test_expect_success 'check split+rejoin' '
275         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
276         undo &&
277         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --rejoin &&
278         check_equal ''"$(last_commit_message)"'' "Split '"'"'sub dir/'"'"' into commit '"'"'"$spl1"'"'"'"
279 '
280
281 test_expect_success 'add main-sub8' '
282         create "sub dir/main-sub8" &&
283         git commit -m "main-sub8"
284 '
285
286 # To the subproject!
287 cd ./"sub proj"
288
289 test_expect_success 'merge split into subproj' '
290         git fetch .. spl1 &&
291         git branch spl1 FETCH_HEAD &&
292         git merge FETCH_HEAD
293 '
294
295 test_expect_success 'add sub9' '
296         create sub9 &&
297         git commit -m "sub9"
298 '
299
300 # Back to mainline
301 cd ..
302
303 test_expect_success 'split for sub8' '
304         split2=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir/" --rejoin)"'' &&
305         git branch split2 "$split2"
306 '
307
308 test_expect_success 'add main-sub10' '
309         create "sub dir/main-sub10" &&
310         git commit -m "main-sub10"
311 '
312
313 test_expect_success 'split for sub10' '
314         spl3=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --rejoin)"'' &&
315         git branch spl3 "$spl3"
316 '
317
318 # To the subproject!
319 cd ./"sub proj"
320
321 test_expect_success 'merge split into subproj' '
322         git fetch .. spl3 &&
323         git branch spl3 FETCH_HEAD &&
324         git merge FETCH_HEAD &&
325         git branch subproj-merge-spl3
326 '
327
328 chkm="main4
329 main6"
330
331 chkms="main-sub10
332 main-sub5
333 main-sub7
334 main-sub8"
335
336 chkms_sub=$(cat <<TXT | sed 's,^,sub dir/,'
337 $chkms
338 TXT
339 )
340
341 chks="sub1
342 sub2
343 sub3
344 sub9"
345
346 chks_sub=$(cat <<TXT | sed 's,^,sub dir/,'
347 $chks
348 TXT
349 )
350
351 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
352         subfiles="$(git ls-files)" &&
353         check_equal "$subfiles" "$chkms
354 $chks"
355 '
356
357 test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
358         allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' &&
359         check_equal "$allchanges" "$chkms
360 $chks"
361 '
362
363 # Back to mainline
364 cd ..
365
366 test_expect_success 'pull from subproj' '
367         git fetch ./"sub proj" subproj-merge-spl3 &&
368         git branch subproj-merge-spl3 FETCH_HEAD &&
369         git subtree pull --prefix="sub dir" ./"sub proj" subproj-merge-spl3
370 '
371
372 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
373         mainfiles=$(git ls-files) &&
374         check_equal "$mainfiles" "$chkm
375 $chkms_sub
376 $chks_sub"
377 '
378
379 test_expect_success 'make sure each filename changed exactly once in the entire history' '
380         # main-sub?? and sub dir/main-sub?? both change, because those are the
381         # changes that were split into their own history.  And sub dir/sub?? never
382         # change, since they were *only* changed in the subtree branch.
383         allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' &&
384         expected=''"$(cat <<TXT | sort
385 $chkms
386 $chkm
387 $chks
388 $chkms_sub
389 TXT
390 )"'' &&
391         check_equal "$allchanges" "$expected"
392 '
393
394 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
395         check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
396 '
397
398 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
399         # They are meaningless to subproj since one side of the merge refers to the mainline
400         check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
401 '
402
403 # prepare second pair of repositories
404 mkdir test2
405 cd test2
406
407 test_expect_success 'init main' '
408         test_create_repo main
409 '
410
411 cd main
412
413 test_expect_success 'add main1' '
414         create main1 &&
415         git commit -m "main1"
416 '
417
418 cd ..
419
420 test_expect_success 'init sub' '
421         test_create_repo sub
422 '
423
424 cd sub
425
426 test_expect_success 'add sub2' '
427         create sub2 &&
428         git commit -m "sub2"
429 '
430
431 cd ../main
432
433 # check if split can find proper base without --onto
434
435 test_expect_success 'add sub as subdir in main' '
436         git fetch ../sub master &&
437         git branch sub2 FETCH_HEAD &&
438         git subtree add --prefix "sub dir" sub2
439 '
440
441 cd ../sub
442
443 test_expect_success 'add sub3' '
444         create sub3 &&
445         git commit -m "sub3"
446 '
447
448 cd ../main
449
450 test_expect_success 'merge from sub' '
451         git fetch ../sub master &&
452         git branch sub3 FETCH_HEAD &&
453         git subtree merge --prefix "sub dir" sub3
454 '
455
456 test_expect_success 'add main-sub4' '
457         create "sub dir/main-sub4" &&
458         git commit -m "main-sub4"
459 '
460
461 test_expect_success 'split for main-sub4 without --onto' '
462         git subtree split --prefix "sub dir" --branch mainsub4
463 '
464
465 # At this point, the new commit parent should be sub3.  If it is not,
466 # something went wrong (the "newparent" of "master~" commit should
467 # have been sub3, but it was not, because its cache was not set to
468 # itself).
469
470 test_expect_success 'check that the commit parent is sub3' '
471         check_equal "$(git log --pretty=format:%P -1 mainsub4)" "$(git rev-parse sub3)"
472 '
473
474 test_expect_success 'add main-sub5' '
475         mkdir subdir2 &&
476         create subdir2/main-sub5 &&
477         git commit -m "main-sub5"
478 '
479
480 test_expect_success 'split for main-sub5 without --onto' '
481         # also test that we still can split out an entirely new subtree
482         # if the parent of the first commit in the tree is not empty,
483         # then the new subtree has accidentally been attached to something
484         git subtree split --prefix subdir2 --branch mainsub5 &&
485         check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
486 '
487
488 test_expect_success 'verify one file change per commit' '
489         x= &&
490         list=''"$(git log --pretty=format:'"'commit: %H'"' | join_commits)"'' &&
491 #       test_debug "echo HERE" &&
492 #       test_debug "echo ''"$list"''" &&
493         git log --pretty=format:'"'commit: %H'"' | join_commits |
494         (       while read commit a b; do
495                         test_debug "echo Verifying commit "''"$commit"''
496                         test_debug "echo a: "''"$a"''
497                         test_debug "echo b: "''"$b"''
498                         check_equal "$b" ""
499                         x=1
500                 done
501                 check_equal "$x" "1"
502         )
503 '
504
505 # test push
506
507 cd ../..
508
509 mkdir -p test-push
510
511 cd test-push
512
513 test_expect_success 'init main' '
514         test_create_repo main
515 '
516
517 test_expect_success 'init sub' '
518         test_create_repo "sub project"
519 '
520
521 cd ./"sub project"
522
523 test_expect_success 'add subproject' '
524         create "sub project" &&
525         git commit -m "Sub project: 1" &&
526         git branch sub-branch-1
527 '
528
529 cd ../main
530
531 test_expect_success 'make first commit and add subproject' '
532         create "main-1" &&
533         git commit -m "main: 1" &&
534         git subtree add "../sub project" --prefix "sub dir" --message "Added subproject" sub-branch-1 &&
535         check_equal "$(last_commit_message)" "Added subproject"
536 '
537
538 test_expect_success 'make second commit to a subproject file and push it into a sub project' '
539         create "sub dir/sub1" &&
540         git commit -m "Sub project: 2" &&
541         git subtree push "../sub project" --prefix "sub dir" sub-branch-1
542 '
543
544 cd ../"sub project"
545
546 test_expect_success 'Test second commit is pushed' '
547         git checkout sub-branch-1 &&
548         check_equal "$(last_commit_message)" "Sub project: 2"
549 '
550
551 test_done