[PATCH] A test case that demonstrates a problem with merges with two roots.
[git.git] / t / t6001-rev-list-merge-order.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Jon Seymour
4 #
5
6 test_description='Tests git-rev-list --merge-order functionality'
7
8 . ./test-lib.sh
9
10 #
11 # TODO: move the following block (upto --- end ...) into testlib.sh
12 #
13 [ -d .git/refs/tags ] || mkdir -p .git/refs/tags
14
15 sed_script="";
16
17 # Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
18 tag()
19 {
20         _tag=$1
21         [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
22         cat .git/refs/tags/$_tag
23 }
24
25 # Generate a commit using the text specified to make it unique and the tree
26 # named by the tag specified.
27 unique_commit()
28 {
29         _text=$1
30         _tree=$2
31         shift 2
32         echo $_text | git-commit-tree $(tag $_tree) "$@"
33 }
34
35 # Save the output of a command into the tag specified. Prepend
36 # a substitution script for the tag onto the front of $sed_script
37 save_tag()
38 {
39         _tag=$1 
40         [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
41         shift 1
42         "$@" >.git/refs/tags/$_tag
43         sed_script="s/$(tag $_tag)/$_tag/g${sed_script+;}$sed_script"
44 }
45
46 # Replace unhelpful sha1 hashses with their symbolic equivalents 
47 entag()
48 {
49         sed "$sed_script"
50 }
51
52 # Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
53 # tag to a specified value. Restore the original value on return.
54 as_author()
55 {
56         _author=$1
57         shift 1
58         _save=$GIT_AUTHOR_EMAIL
59
60         export GIT_AUTHOR_EMAIL="$_author"
61         "$@"
62         export GIT_AUTHOR_EMAIL="$_save"
63 }
64
65 commit_date()
66 {
67         _commit=$1
68         git-cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" 
69 }
70
71 on_committer_date()
72 {
73     _date=$1
74     shift 1
75     GIT_COMMITTER_DATE=$_date "$@"
76 }
77
78 # Execute a command and suppress any error output.
79 hide_error()
80 {
81         "$@" 2>/dev/null
82 }
83
84 check_output()
85 {
86         _name=$1
87         shift 1
88         if "$@" | entag > $_name.actual
89         then
90                 diff $_name.expected $_name.actual
91         else
92                 return 1;
93         fi
94         
95 }
96
97 # Turn a reasonable test description into a reasonable test name.
98 # All alphanums translated into -'s which are then compressed and stripped
99 # from front and back.
100 name_from_description()
101 {
102         tr "'" '-' | tr '~`!@#$%^&*()_+={}[]|\;:"<>,/? ' '-' | tr -s '-' | tr '[A-Z]' '[a-z]' | sed "s/^-*//;s/-*\$//"
103 }
104
105
106 # Execute the test described by the first argument, by eval'ing
107 # command line specified in the 2nd argument. Check the status code
108 # is zero and that the output matches the stream read from 
109 # stdin.
110 test_output_expect_success()
111 {       
112         _description=$1
113         _test=$2
114         [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
115         _name=$(echo $_description | name_from_description)
116         cat > $_name.expected
117         test_expect_success "$_description" "check_output $_name $_test" 
118 }
119
120 # --- end of stuff to move ---
121
122 # test-case specific test function
123 check_adjacency()
124 {
125     read previous
126     echo "= $previous"
127     while read next
128     do
129         if ! (git-cat-file commit $previous | grep "^parent $next" >/dev/null)
130         then
131             echo "^ $next"
132         else
133             echo "| $next"
134         fi
135         previous=$next
136     done
137 }
138
139 list_duplicates()
140 {
141     "$@" | sort | uniq -d
142 }
143
144 grep_stderr()
145 {
146     args=$1
147     shift 1
148     "$@" 2>&1 | grep "$args"
149 }
150
151 date >path0
152 git-update-cache --add path0
153 save_tag tree git-write-tree
154 on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
155 on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
156 on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
157 on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
158 on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
159 on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
160 on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
161 on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
162 on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
163 on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
164 on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
165 on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
166 on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
167 on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
168 on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
169 on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
170 on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
171 on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
172 on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
173 on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
174 on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
175 on_committer_date "1971-08-16 00:00:21" hide_error save_tag alt_root unique_commit alt_root tree
176 on_committer_date "1971-08-16 00:00:22" save_tag r0 unique_commit r0 tree -p alt_root
177 on_committer_date "1971-08-16 00:00:23" save_tag r1 unique_commit r1 tree -p r0
178 on_committer_date "1971-08-16 00:00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
179 on_committer_date "1971-08-16 00:00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
180
181
182 #
183 # note: as of 20/6, it isn't possible to create duplicate parents, so this
184 # can't be tested.
185 #
186 #on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
187 hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
188 save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
189 save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
190 save_tag e3 as_author e@example.com unique_commit e3 tree -p e2
191 save_tag f2 as_author f@example.com unique_commit f2 tree -p f1
192 save_tag e4 as_author e@example.com unique_commit e4 tree -p e3 -p f2
193 save_tag e5 as_author e@example.com unique_commit e5 tree -p e4
194 save_tag f3 as_author f@example.com unique_commit f3 tree -p f2
195 save_tag f4 as_author f@example.com unique_commit f4 tree -p f3
196 save_tag e6 as_author e@example.com unique_commit e6 tree -p e5 -p f4
197 save_tag f5 as_author f@example.com unique_commit f5 tree -p f4
198 save_tag f6 as_author f@example.com unique_commit f6 tree -p f5 -p e6
199 save_tag e7 as_author e@example.com unique_commit e7 tree -p e6
200 save_tag e8 as_author e@example.com unique_commit e8 tree -p e7
201 save_tag e9 as_author e@example.com unique_commit e9 tree -p e8
202 save_tag f7 as_author f@example.com unique_commit f7 tree -p f6
203 save_tag f8 as_author f@example.com unique_commit f8 tree -p f7
204 save_tag f9 as_author f@example.com unique_commit f9 tree -p f8
205 save_tag e10 as_author e@example.com unique_commit e1 tree -p e9 -p f8
206
207 hide_error save_tag g0 unique_commit g0 tree
208 save_tag g1 unique_commit g1 tree -p g0
209 save_tag h1 unique_commit g2 tree -p g0
210 save_tag g2 unique_commit g3 tree -p g1 -p h1
211 save_tag h2 unique_commit g4 tree -p g2
212 save_tag g3 unique_commit g5 tree -p g2
213 save_tag g4 unique_commit g6 tree -p g3 -p h2
214
215 tag l5 > .git/HEAD
216
217 #
218 # cd to t/trash and use 
219 #
220 #    git-rev-list ... 2>&1 | sed "$(cat sed.script)" 
221 #
222 # if you ever want to manually debug the operation of git-rev-list
223 #
224 echo $sed_script > sed.script
225
226 test_expect_success 'rev-list has correct number of entries' 'git-rev-list HEAD | wc -l | tr -s " "' <<EOF
227 19
228 EOF
229
230 normal_adjacency_count=$(git-rev-list HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
231 merge_order_adjacency_count=$(git-rev-list --merge-order HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
232 test_expect_success '--merge-order produces as many or fewer discontinuities' '[ $merge_order_adjacency_count -le $normal_adjacency_count ]'
233 test_output_expect_success 'simple merge order' 'git-rev-list --merge-order --show-breaks HEAD' <<EOF
234 = l5
235 | l4
236 | l3
237 = a4
238 | c3
239 | c2
240 | c1
241 ^ b4
242 | b3
243 | b2
244 | b1
245 ^ a3
246 | a2
247 | a1
248 = a0
249 | l2
250 | l1
251 | l0
252 = root
253 EOF
254
255 test_output_expect_success 'two diamonds merge order (g6)' 'git-rev-list --merge-order --show-breaks g4' <<EOF
256 = g4
257 | h2
258 ^ g3
259 = g2
260 | h1
261 ^ g1
262 = g0
263 EOF
264
265 test_output_expect_success 'multiple heads' 'git-rev-list --merge-order a3 b3 c3' <<EOF
266 c3
267 c2
268 c1
269 b3
270 b2
271 b1
272 a3
273 a2
274 a1
275 a0
276 l2
277 l1
278 l0
279 root
280 EOF
281
282 test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --merge-order a3 b3 c3 ^a1' <<EOF
283 c3
284 c2
285 c1
286 b3
287 b2
288 b1
289 a3
290 a2
291 EOF
292
293 test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --merge-order a3 b3 c3 ^l1' <<EOF
294 c3
295 c2
296 c1
297 b3
298 b2
299 b1
300 a3
301 a2
302 a1
303 a0
304 l2
305 EOF
306
307 test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git-rev-list --merge-order l5 ^l1' <<EOF
308 l5
309 l4
310 l3
311 a4
312 c3
313 c2
314 c1
315 b4
316 b3
317 b2
318 b1
319 a3
320 a2
321 a1
322 a0
323 l2
324 EOF
325
326 test_output_expect_success 'duplicated head arguments' 'git-rev-list --merge-order l5 l5 ^l1' <<EOF
327 l5
328 l4
329 l3
330 a4
331 c3
332 c2
333 c1
334 b4
335 b3
336 b2
337 b1
338 a3
339 a2
340 a1
341 a0
342 l2
343 EOF
344
345 test_output_expect_success 'prune near merge' 'git-rev-list --merge-order a4 ^c3' <<EOF
346 a4
347 b4
348 b3
349 a3
350 a2
351 a1
352 EOF
353
354 test_output_expect_success "head has no parent" 'git-rev-list --merge-order --show-breaks root' <<EOF
355 = root
356 EOF
357
358 test_output_expect_success "two nodes - one head, one base" 'git-rev-list --merge-order --show-breaks l0' <<EOF
359 = l0
360 = root
361 EOF
362
363 test_output_expect_success "three nodes one head, one internal, one base" 'git-rev-list --merge-order --show-breaks l1' <<EOF
364 = l1
365 | l0
366 = root
367 EOF
368
369 test_output_expect_success "linear prune l2 ^root" 'git-rev-list --merge-order --show-breaks l2 ^root' <<EOF
370 = l2
371 | l1
372 | l0
373 EOF
374
375 test_output_expect_success "linear prune l2 ^l0" 'git-rev-list --merge-order --show-breaks l2 ^l0' <<EOF
376 = l2
377 | l1
378 EOF
379
380 test_output_expect_success "linear prune l2 ^l1" 'git-rev-list --merge-order --show-breaks l2 ^l1' <<EOF
381 = l2
382 EOF
383
384 test_output_expect_success "linear prune l5 ^a4" 'git-rev-list --merge-order --show-breaks l5 ^a4' <<EOF
385 = l5
386 | l4
387 | l3
388 EOF
389
390 test_output_expect_success "linear prune l5 ^l3" 'git-rev-list --merge-order --show-breaks l5 ^l3' <<EOF
391 = l5
392 | l4
393 EOF
394
395 test_output_expect_success "linear prune l5 ^l4" 'git-rev-list --merge-order --show-breaks l5 ^l4' <<EOF
396 = l5
397 EOF
398
399 test_output_expect_success "max-count 10 - merge order" 'git-rev-list --merge-order --show-breaks --max-count=10 l5' <<EOF
400 = l5
401 | l4
402 | l3
403 = a4
404 | c3
405 | c2
406 | c1
407 ^ b4
408 | b3
409 | b2
410 EOF
411
412 test_output_expect_success "max-count 10 - non merge order" 'git-rev-list --max-count=10 l5 | sort' <<EOF
413 a4
414 b2
415 b3
416 b4
417 c1
418 c2
419 c3
420 l3
421 l4
422 l5
423 EOF
424
425 test_output_expect_success '--max-age=c3, no --merge-order' "git-rev-list --max-age=$(commit_date c3) l5" <<EOF
426 l5
427 l4
428 l3
429 a4
430 b4
431 a3
432 a2
433 c3
434 EOF
435
436 test_output_expect_success '--max-age=c3, --merge-order' "git-rev-list --merge-order --max-age=$(commit_date c3) l5" <<EOF
437 l5
438 l4
439 l3
440 a4
441 c3
442 b4
443 a3
444 a2
445 EOF
446
447 test_output_expect_success 'one specified head reachable from another a4, c3, --merge-order' "list_duplicates git-rev-list --merge-order a4 c3" <<EOF
448 EOF
449
450 test_output_expect_success 'one specified head reachable from another c3, a4, --merge-order' "list_duplicates git-rev-list --merge-order c3 a4" <<EOF
451 EOF
452
453 test_output_expect_success 'one specified head reachable from another a4, c3, no --merge-order' "list_duplicates git-rev-list a4 c3" <<EOF
454 EOF
455
456 test_output_expect_success 'one specified head reachable from another c3, a4, no --merge-order' "list_duplicates git-rev-list c3 a4" <<EOF
457 EOF
458
459 test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git-rev-list m1" <<EOF
460 EOF
461
462 test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git-rev-list m2" <<EOF
463 EOF
464
465 test_expect_success "head ^head --merge-order" 'git-rev-list --merge-order --show-breaks a3 ^a3' <<EOF
466 EOF
467
468 #
469 # can't test this now - duplicate parents can't be created
470 #
471 #test_output_expect_success 'duplicate parents' 'git-rev-list --parents --merge-order --show-breaks m3' <<EOF
472 #= m3 c3 a4 c3
473 #| a4 c3 b4 a3
474 #| b4 a3 b3
475 #| b3 b2
476 #^ a3 a2
477 #| a2 a1
478 #| a1 a0
479 #^ c3 c2
480 #| c2 b2 c1
481 #| b2 b1
482 #^ c1 b1
483 #| b1 a0
484 #= a0 l2
485 #| l2 l1
486 #| l1 l0
487 #| l0 root
488 #= root
489 #EOF
490
491 test_expect_success "head ^head no --merge-order" 'git-rev-list a3 ^a3' <<EOF
492 EOF
493
494 test_output_expect_success 'simple merge order (l5r1)' 'git-rev-list --merge-order --show-breaks l5r1' <<EOF
495 = l5r1
496 | r1
497 | r0
498 | alt_root
499 ^ l5
500 | l4
501 | l3
502 | a4
503 | c3
504 | c2
505 | c1
506 ^ b4
507 | b3
508 | b2
509 | b1
510 ^ a3
511 | a2
512 | a1
513 | a0
514 | l2
515 | l1
516 | l0
517 = root
518 EOF
519
520 test_output_expect_success 'simple merge order (r1l5)' 'git-rev-list --merge-order --show-breaks r1l5' <<EOF
521 = r1l5
522 | l5
523 | l4
524 | l3
525 | a4
526 | c3
527 | c2
528 | c1
529 ^ b4
530 | b3
531 | b2
532 | b1
533 ^ a3
534 | a2
535 | a1
536 | a0
537 | l2
538 | l1
539 | l0
540 | root
541 ^ r1
542 | r0
543 = alt_root
544 EOF
545
546
547 #
548 #
549
550 test_done