t / t6001-rev-list-merge-order.shon commit Do a cross-project merge of Paul Mackerras' gitk visualizer (5569bf9)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Jon Seymour
   4#
   5
   6test_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
  15sed_script="";
  16
  17# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
  18tag()
  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.
  27unique_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
  37save_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 
  47entag()
  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.
  54as_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
  65commit_date()
  66{
  67        _commit=$1
  68        git-cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" 
  69}
  70
  71on_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.
  79hide_error()
  80{
  81        "$@" 2>/dev/null
  82}
  83
  84check_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.
 100name_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.
 110test_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
 123check_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
 139list_duplicates()
 140{
 141    "$@" | sort | uniq -d
 142}
 143
 144grep_stderr()
 145{
 146    args=$1
 147    shift 1
 148    "$@" 2>&1 | grep "$args"
 149}
 150
 151date >path0
 152git-update-cache --add path0
 153save_tag tree git-write-tree
 154on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
 155on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
 156on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
 157on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
 158on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
 159on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
 160on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
 161on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
 162on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
 163on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
 164on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
 165on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
 166on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
 167on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
 168on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
 169on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
 170on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
 171on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
 172on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
 173on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
 174on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
 175#
 176# note: as of 20/6, it isn't possible to create duplicate parents, so this
 177# can't be tested.
 178#
 179#on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
 180hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
 181save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
 182save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
 183save_tag e3 as_author e@example.com unique_commit e3 tree -p e2
 184save_tag f2 as_author f@example.com unique_commit f2 tree -p f1
 185save_tag e4 as_author e@example.com unique_commit e4 tree -p e3 -p f2
 186save_tag e5 as_author e@example.com unique_commit e5 tree -p e4
 187save_tag f3 as_author f@example.com unique_commit f3 tree -p f2
 188save_tag f4 as_author f@example.com unique_commit f4 tree -p f3
 189save_tag e6 as_author e@example.com unique_commit e6 tree -p e5 -p f4
 190save_tag f5 as_author f@example.com unique_commit f5 tree -p f4
 191save_tag f6 as_author f@example.com unique_commit f6 tree -p f5 -p e6
 192save_tag e7 as_author e@example.com unique_commit e7 tree -p e6
 193save_tag e8 as_author e@example.com unique_commit e8 tree -p e7
 194save_tag e9 as_author e@example.com unique_commit e9 tree -p e8
 195save_tag f7 as_author f@example.com unique_commit f7 tree -p f6
 196save_tag f8 as_author f@example.com unique_commit f8 tree -p f7
 197save_tag f9 as_author f@example.com unique_commit f9 tree -p f8
 198save_tag e10 as_author e@example.com unique_commit e1 tree -p e9 -p f8
 199
 200hide_error save_tag g0 unique_commit g0 tree
 201save_tag g1 unique_commit g1 tree -p g0
 202save_tag h1 unique_commit g2 tree -p g0
 203save_tag g2 unique_commit g3 tree -p g1 -p h1
 204save_tag h2 unique_commit g4 tree -p g2
 205save_tag g3 unique_commit g5 tree -p g2
 206save_tag g4 unique_commit g6 tree -p g3 -p h2
 207
 208tag l5 > .git/HEAD
 209
 210#
 211# cd to t/trash and use 
 212#
 213#    git-rev-list ... 2>&1 | sed "$(cat sed.script)" 
 214#
 215# if you ever want to manually debug the operation of git-rev-list
 216#
 217echo $sed_script > sed.script
 218
 219test_expect_success 'rev-list has correct number of entries' 'git-rev-list HEAD | wc -l | tr -s " "' <<EOF
 22019
 221EOF
 222
 223normal_adjacency_count=$(git-rev-list HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
 224merge_order_adjacency_count=$(git-rev-list --merge-order HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
 225test_expect_success '--merge-order produces as many or fewer discontinuities' '[ $merge_order_adjacency_count -le $normal_adjacency_count ]'
 226test_output_expect_success 'simple merge order' 'git-rev-list --merge-order --show-breaks HEAD' <<EOF
 227= l5
 228| l4
 229| l3
 230= a4
 231| c3
 232| c2
 233| c1
 234^ b4
 235| b3
 236| b2
 237| b1
 238^ a3
 239| a2
 240| a1
 241= a0
 242| l2
 243| l1
 244| l0
 245= root
 246EOF
 247
 248test_output_expect_success 'two diamonds merge order (g6)' 'git-rev-list --merge-order --show-breaks g4' <<EOF
 249= g4
 250| h2
 251^ g3
 252= g2
 253| h1
 254^ g1
 255= g0
 256EOF
 257
 258test_output_expect_success 'multiple heads' 'git-rev-list --merge-order a3 b3 c3' <<EOF
 259c3
 260c2
 261c1
 262b3
 263b2
 264b1
 265a3
 266a2
 267a1
 268a0
 269l2
 270l1
 271l0
 272root
 273EOF
 274
 275test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --merge-order a3 b3 c3 ^a1' <<EOF
 276c3
 277c2
 278c1
 279b3
 280b2
 281b1
 282a3
 283a2
 284EOF
 285
 286test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --merge-order a3 b3 c3 ^l1' <<EOF
 287c3
 288c2
 289c1
 290b3
 291b2
 292b1
 293a3
 294a2
 295a1
 296a0
 297l2
 298EOF
 299
 300test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git-rev-list --merge-order l5 ^l1' <<EOF
 301l5
 302l4
 303l3
 304a4
 305c3
 306c2
 307c1
 308b4
 309b3
 310b2
 311b1
 312a3
 313a2
 314a1
 315a0
 316l2
 317EOF
 318
 319test_output_expect_success 'duplicated head arguments' 'git-rev-list --merge-order l5 l5 ^l1' <<EOF
 320l5
 321l4
 322l3
 323a4
 324c3
 325c2
 326c1
 327b4
 328b3
 329b2
 330b1
 331a3
 332a2
 333a1
 334a0
 335l2
 336EOF
 337
 338test_output_expect_success 'prune near merge' 'git-rev-list --merge-order a4 ^c3' <<EOF
 339a4
 340b4
 341b3
 342a3
 343a2
 344a1
 345EOF
 346
 347test_output_expect_success "head has no parent" 'git-rev-list --merge-order --show-breaks root' <<EOF
 348= root
 349EOF
 350
 351test_output_expect_success "two nodes - one head, one base" 'git-rev-list --merge-order --show-breaks l0' <<EOF
 352= l0
 353= root
 354EOF
 355
 356test_output_expect_success "three nodes one head, one internal, one base" 'git-rev-list --merge-order --show-breaks l1' <<EOF
 357= l1
 358| l0
 359= root
 360EOF
 361
 362test_output_expect_success "linear prune l2 ^root" 'git-rev-list --merge-order --show-breaks l2 ^root' <<EOF
 363= l2
 364| l1
 365| l0
 366EOF
 367
 368test_output_expect_success "linear prune l2 ^l0" 'git-rev-list --merge-order --show-breaks l2 ^l0' <<EOF
 369= l2
 370| l1
 371EOF
 372
 373test_output_expect_success "linear prune l2 ^l1" 'git-rev-list --merge-order --show-breaks l2 ^l1' <<EOF
 374= l2
 375EOF
 376
 377test_output_expect_success "linear prune l5 ^a4" 'git-rev-list --merge-order --show-breaks l5 ^a4' <<EOF
 378= l5
 379| l4
 380| l3
 381EOF
 382
 383test_output_expect_success "linear prune l5 ^l3" 'git-rev-list --merge-order --show-breaks l5 ^l3' <<EOF
 384= l5
 385| l4
 386EOF
 387
 388test_output_expect_success "linear prune l5 ^l4" 'git-rev-list --merge-order --show-breaks l5 ^l4' <<EOF
 389= l5
 390EOF
 391
 392test_output_expect_success "max-count 10 - merge order" 'git-rev-list --merge-order --show-breaks --max-count=10 l5' <<EOF
 393= l5
 394| l4
 395| l3
 396= a4
 397| c3
 398| c2
 399| c1
 400^ b4
 401| b3
 402| b2
 403EOF
 404
 405test_output_expect_success "max-count 10 - non merge order" 'git-rev-list --max-count=10 l5 | sort' <<EOF
 406a4
 407b2
 408b3
 409b4
 410c1
 411c2
 412c3
 413l3
 414l4
 415l5
 416EOF
 417
 418test_output_expect_success '--max-age=c3, no --merge-order' "git-rev-list --max-age=$(commit_date c3) l5" <<EOF
 419l5
 420l4
 421l3
 422a4
 423b4
 424a3
 425a2
 426c3
 427EOF
 428
 429test_output_expect_success '--max-age=c3, --merge-order' "git-rev-list --merge-order --max-age=$(commit_date c3) l5" <<EOF
 430l5
 431l4
 432l3
 433a4
 434c3
 435b4
 436a3
 437a2
 438EOF
 439
 440test_output_expect_success 'one specified head reachable from another a4, c3, --merge-order' "list_duplicates git-rev-list --merge-order a4 c3" <<EOF
 441EOF
 442
 443test_output_expect_success 'one specified head reachable from another c3, a4, --merge-order' "list_duplicates git-rev-list --merge-order c3 a4" <<EOF
 444EOF
 445
 446test_output_expect_success 'one specified head reachable from another a4, c3, no --merge-order' "list_duplicates git-rev-list a4 c3" <<EOF
 447EOF
 448
 449test_output_expect_success 'one specified head reachable from another c3, a4, no --merge-order' "list_duplicates git-rev-list c3 a4" <<EOF
 450EOF
 451
 452test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git-rev-list m1" <<EOF
 453EOF
 454
 455test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git-rev-list m2" <<EOF
 456EOF
 457
 458test_expect_success "head ^head --merge-order" 'git-rev-list --merge-order --show-breaks a3 ^a3' <<EOF
 459EOF
 460
 461#
 462# can't test this now - duplicate parents can't be created
 463#
 464#test_output_expect_success 'duplicate parents' 'git-rev-list --parents --merge-order --show-breaks m3' <<EOF
 465#= m3 c3 a4 c3
 466#| a4 c3 b4 a3
 467#| b4 a3 b3
 468#| b3 b2
 469#^ a3 a2
 470#| a2 a1
 471#| a1 a0
 472#^ c3 c2
 473#| c2 b2 c1
 474#| b2 b1
 475#^ c1 b1
 476#| b1 a0
 477#= a0 l2
 478#| l2 l1
 479#| l1 l0
 480#| l0 root
 481#= root
 482#EOF
 483
 484test_expect_success "head ^head no --merge-order" 'git-rev-list a3 ^a3' <<EOF
 485EOF
 486#
 487#
 488
 489test_done