contrib/subtree: Add test for missing subtree
[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 'check if --message works for add' '
131         git subtree add --prefix="sub dir" --message="Added subproject" sub1 &&
132         check_equal ''"$(last_commit_message)"'' "Added subproject" &&
133         undo
134 '
135
136 test_expect_success 'check if --message works as -m and --prefix as -P' '
137         git subtree add -P "sub dir" -m "Added subproject using git subtree" sub1 &&
138         check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
139         undo
140 '
141
142 test_expect_success 'check if --message works with squash too' '
143         git subtree add -P "sub dir" -m "Added subproject with squash" --squash sub1 &&
144         check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
145         undo
146 '
147
148 test_expect_success 'add subproj to mainline' '
149         git subtree add --prefix="sub dir"/ FETCH_HEAD &&
150         check_equal ''"$(last_commit_message)"'' "Add '"'sub dir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
151 '
152
153 test_expect_success 'merge the added subproj again, should do nothing' '
154         # this shouldn not actually do anything, since FETCH_HEAD
155         # is already a parent
156         result=$(git merge -s ours -m "merge -s -ours" FETCH_HEAD) &&
157         check_equal "${result}" "Already up-to-date."
158 '
159
160 test_expect_success 'add main-sub5' '
161         create "sub dir/main-sub5" &&
162         git commit -m "main-sub5"
163 '
164
165 test_expect_success 'add main6' '
166         create main6 &&
167         git commit -m "main6 boring"
168 '
169
170 test_expect_success 'add main-sub7' '
171         create "sub dir/main-sub7" &&
172         git commit -m "main-sub7"
173 '
174
175 test_expect_success 'fetch new subproj history' '
176         git fetch ./"sub proj" sub2 &&
177         git branch sub2 FETCH_HEAD
178 '
179
180 test_expect_success 'check if --message works for merge' '
181         git subtree merge --prefix="sub dir" -m "Merged changes from subproject" sub2 &&
182         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
183         undo
184 '
185
186 test_expect_success 'check if --message for merge works with squash too' '
187         git subtree merge --prefix "sub dir" -m "Merged changes from subproject using squash" --squash sub2 &&
188         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
189         undo
190 '
191
192 test_expect_success 'merge new subproj history into subdir' '
193         git subtree merge --prefix="sub dir" FETCH_HEAD &&
194         git branch pre-split &&
195         check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" &&
196         undo
197 '
198
199 test_expect_success 'split requires option --prefix' '
200         echo "You must provide the --prefix option." > expected &&
201         test_must_fail git subtree split > actual 2>&1 &&
202         test_debug "printf '"'"'expected: '"'"'" &&
203         test_debug "cat expected" &&
204         test_debug "printf '"'"'actual: '"'"'" &&
205         test_debug "cat actual" &&
206         test_cmp expected actual &&
207         rm -f expected actual
208 '
209
210 test_expect_success 'split requires path given by option --prefix must exist' '
211         echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
212         test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
213         test_debug "printf '"'"'expected: '"'"'" &&
214         test_debug "cat expected" &&
215         test_debug "printf '"'"'actual: '"'"'" &&
216         test_debug "cat actual" &&
217         test_cmp expected actual &&
218         rm -f expected actual
219 '
220
221 test_expect_success 'check if --message works for split+rejoin' '
222         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
223         git branch spl1 "$spl1" &&
224         check_equal ''"$(last_commit_message)"'' "Split & rejoin" &&
225         undo
226 '
227
228 test_expect_success 'check split with --branch' '
229         spl1=$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin) &&
230         undo &&
231         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr1 &&
232         check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
233 '
234
235 test_expect_success 'check hash of split' '
236         spl1=$(git subtree split --prefix "sub dir") &&
237         git subtree split --prefix "sub dir" --branch splitbr1test &&
238         check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1" &&
239         new_hash=$(git rev-parse splitbr1test~2) &&
240         check_equal ''"$new_hash"'' "$subdir_hash"
241 '
242
243 test_expect_success 'check split with --branch for an existing branch' '
244         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
245         undo &&
246         git branch splitbr2 sub1 &&
247         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr2 &&
248         check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
249 '
250
251 test_expect_success 'check split with --branch for an incompatible branch' '
252         test_must_fail git subtree split --prefix "sub dir" --onto FETCH_HEAD --branch subdir
253 '
254
255 test_expect_success 'check split+rejoin' '
256         spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
257         undo &&
258         git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --rejoin &&
259         check_equal ''"$(last_commit_message)"'' "Split '"'"'sub dir/'"'"' into commit '"'"'"$spl1"'"'"'"
260 '
261
262 test_expect_success 'add main-sub8' '
263         create "sub dir/main-sub8" &&
264         git commit -m "main-sub8"
265 '
266
267 # To the subproject!
268 cd ./"sub proj"
269
270 test_expect_success 'merge split into subproj' '
271         git fetch .. spl1 &&
272         git branch spl1 FETCH_HEAD &&
273         git merge FETCH_HEAD
274 '
275
276 test_expect_success 'add sub9' '
277         create sub9 &&
278         git commit -m "sub9"
279 '
280
281 # Back to mainline
282 cd ..
283
284 test_expect_success 'split for sub8' '
285         split2=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir/" --rejoin)"'' &&
286         git branch split2 "$split2"
287 '
288
289 test_expect_success 'add main-sub10' '
290         create "sub dir/main-sub10" &&
291         git commit -m "main-sub10"
292 '
293
294 test_expect_success 'split for sub10' '
295         spl3=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --rejoin)"'' &&
296         git branch spl3 "$spl3"
297 '
298
299 # To the subproject!
300 cd ./"sub proj"
301
302 test_expect_success 'merge split into subproj' '
303         git fetch .. spl3 &&
304         git branch spl3 FETCH_HEAD &&
305         git merge FETCH_HEAD &&
306         git branch subproj-merge-spl3
307 '
308
309 chkm="main4
310 main6"
311
312 chkms="main-sub10
313 main-sub5
314 main-sub7
315 main-sub8"
316
317 chkms_sub=$(cat <<TXT | sed 's,^,sub dir/,'
318 $chkms
319 TXT
320 )
321
322 chks="sub1
323 sub2
324 sub3
325 sub9"
326
327 chks_sub=$(cat <<TXT | sed 's,^,sub dir/,'
328 $chks
329 TXT
330 )
331
332 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
333         subfiles="$(git ls-files)" &&
334         check_equal "$subfiles" "$chkms
335 $chks"
336 '
337
338 test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
339         allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' &&
340         check_equal "$allchanges" "$chkms
341 $chks"
342 '
343
344 # Back to mainline
345 cd ..
346
347 test_expect_success 'pull from subproj' '
348         git fetch ./"sub proj" subproj-merge-spl3 &&
349         git branch subproj-merge-spl3 FETCH_HEAD &&
350         git subtree pull --prefix="sub dir" ./"sub proj" subproj-merge-spl3
351 '
352
353 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
354         mainfiles=$(git ls-files) &&
355         check_equal "$mainfiles" "$chkm
356 $chkms_sub
357 $chks_sub"
358 '
359
360 test_expect_success 'make sure each filename changed exactly once in the entire history' '
361         # main-sub?? and sub dir/main-sub?? both change, because those are the
362         # changes that were split into their own history.  And sub dir/sub?? never
363         # change, since they were *only* changed in the subtree branch.
364         allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' &&
365         expected=''"$(cat <<TXT | sort
366 $chkms
367 $chkm
368 $chks
369 $chkms_sub
370 TXT
371 )"'' &&
372         check_equal "$allchanges" "$expected"
373 '
374
375 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
376         check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
377 '
378
379 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
380         # They are meaningless to subproj since one side of the merge refers to the mainline
381         check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
382 '
383
384 # prepare second pair of repositories
385 mkdir test2
386 cd test2
387
388 test_expect_success 'init main' '
389         test_create_repo main
390 '
391
392 cd main
393
394 test_expect_success 'add main1' '
395         create main1 &&
396         git commit -m "main1"
397 '
398
399 cd ..
400
401 test_expect_success 'init sub' '
402         test_create_repo sub
403 '
404
405 cd sub
406
407 test_expect_success 'add sub2' '
408         create sub2 &&
409         git commit -m "sub2"
410 '
411
412 cd ../main
413
414 # check if split can find proper base without --onto
415
416 test_expect_success 'add sub as subdir in main' '
417         git fetch ../sub master &&
418         git branch sub2 FETCH_HEAD &&
419         git subtree add --prefix "sub dir" sub2
420 '
421
422 cd ../sub
423
424 test_expect_success 'add sub3' '
425         create sub3 &&
426         git commit -m "sub3"
427 '
428
429 cd ../main
430
431 test_expect_success 'merge from sub' '
432         git fetch ../sub master &&
433         git branch sub3 FETCH_HEAD &&
434         git subtree merge --prefix "sub dir" sub3
435 '
436
437 test_expect_success 'add main-sub4' '
438         create "sub dir/main-sub4" &&
439         git commit -m "main-sub4"
440 '
441
442 test_expect_success 'split for main-sub4 without --onto' '
443         git subtree split --prefix "sub dir" --branch mainsub4
444 '
445
446 # At this point, the new commit parent should be sub3.  If it is not,
447 # something went wrong (the "newparent" of "master~" commit should
448 # have been sub3, but it was not, because its cache was not set to
449 # itself).
450
451 test_expect_success 'check that the commit parent is sub3' '
452         check_equal "$(git log --pretty=format:%P -1 mainsub4)" "$(git rev-parse sub3)"
453 '
454
455 test_expect_success 'add main-sub5' '
456         mkdir subdir2 &&
457         create subdir2/main-sub5 &&
458         git commit -m "main-sub5"
459 '
460
461 test_expect_success 'split for main-sub5 without --onto' '
462         # also test that we still can split out an entirely new subtree
463         # if the parent of the first commit in the tree is not empty,
464         # then the new subtree has accidentally been attached to something
465         git subtree split --prefix subdir2 --branch mainsub5 &&
466         check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
467 '
468
469 test_expect_success 'verify one file change per commit' '
470         x= &&
471         list=''"$(git log --pretty=format:'"'commit: %H'"' | join_commits)"'' &&
472 #       test_debug "echo HERE" &&
473 #       test_debug "echo ''"$list"''" &&
474         git log --pretty=format:'"'commit: %H'"' | join_commits |
475         (       while read commit a b; do
476                         test_debug "echo Verifying commit "''"$commit"''
477                         test_debug "echo a: "''"$a"''
478                         test_debug "echo b: "''"$b"''
479                         check_equal "$b" ""
480                         x=1
481                 done
482                 check_equal "$x" "1"
483         )
484 '
485
486 # test push
487
488 cd ../..
489
490 mkdir -p test-push
491
492 cd test-push
493
494 test_expect_success 'init main' '
495         test_create_repo main
496 '
497
498 test_expect_success 'init sub' '
499         test_create_repo "sub project"
500 '
501
502 cd ./"sub project"
503
504 test_expect_success 'add subproject' '
505         create "sub project" &&
506         git commit -m "Sub project: 1" &&
507         git branch sub-branch-1
508 '
509
510 cd ../main
511
512 test_expect_success 'make first commit and add subproject' '
513         create "main-1" &&
514         git commit -m "main: 1" &&
515         git subtree add "../sub project" --prefix "sub dir" --message "Added subproject" sub-branch-1 &&
516         check_equal "$(last_commit_message)" "Added subproject"
517 '
518
519 test_expect_success 'make second commit to a subproject file and push it into a sub project' '
520         create "sub dir/sub1" &&
521         git commit -m "Sub project: 2" &&
522         git subtree push "../sub project" --prefix "sub dir" sub-branch-1
523 '
524
525 cd ../"sub project"
526
527 test_expect_success 'Test second commit is pushed' '
528         git checkout sub-branch-1 &&
529         check_equal "$(last_commit_message)" "Sub project: 2"
530 '
531
532 test_done