(command.CommandList
  children: [
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:test_description)
          op: assign_op.Equal
          rhs: {(SQ (Token id:Id.Lit_Chars val:'diff function context' span_id:6))}
          spids: [4]
        )
      ]
    )
    (C {(.)} {(./test-lib.sh)})
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:dir)
          op: assign_op.Equal
          rhs: {(DQ ($ Id.VSub_DollarName '$TEST_DIRECTORY') (/t4051))}
          spids: [15]
        )
      ]
    )
    (command.ShFunction
      name: commit_and_tag
      body: 
        (command.BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:tag)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$1')}
                      spids: [30]
                    )
                  ]
                )
                (C {(shift)})
                (C {(git)} {(add)} {(DQ ($ Id.VSub_At '$@'))})
                (C {(test_tick)})
                (C {(git)} {(commit)} {(-m)} {(DQ ($ Id.VSub_DollarName '$tag'))})
                (C {(git)} {(tag)} {(DQ ($ Id.VSub_DollarName '$tag'))})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: first_context_line
      body: 
        (command.BraceGroup
          children: [
            (C {(awk)} 
              {
                (SQ (Token id:Id.Lit_Chars val:'\n' span_id:92) 
                  (Token
                    id: Id.Lit_Chars
                    val: '\t\tfound {print; exit}\n'
                    span_id: 93
                  ) (Token id:Id.Lit_Chars val:'\t\t/^@@/ {found = 1}\n' span_id:94) 
                  (Token id:Id.Lit_Chars val:'\t' span_id:95)
                )
              }
            )
          ]
        )
    )
    (command.ShFunction
      name: last_context_line
      body: 
        (command.BraceGroup
          children: [
            (C {(sed)} {(-ne)} 
              {(word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:'\\$' span_id:113)) 
                (p)
              }
            )
          ]
        )
    )
    (command.ShFunction
      name: check_diff
      body: 
        (command.BraceGroup
          children: [
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:name)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$1')}
                  spids: [127]
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:desc)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$2')}
                  spids: [131]
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:options)
                  op: assign_op.Equal
                  rhs: {(DQ ('-W ') ($ Id.VSub_Number '$3'))}
                  spids: [135]
                )
              ]
            )
            (C {(test_expect_success)} {(DQ ($ Id.VSub_DollarName '$desc'))} 
              {
                (SQ (Token id:Id.Lit_Chars val:'\n' span_id:150) 
                  (Token
                    id: Id.Lit_Chars
                    val: '\t\tgit diff $options "$name^" "$name" >"$name.diff"\n'
                    span_id: 151
                  ) (Token id:Id.Lit_Chars val:'\t' span_id:152)
                )
              }
            )
            (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' diff applies' span_id:160))} 
              {
                (SQ (Token id:Id.Lit_Chars val:'\n' span_id:164) 
                  (Token
                    id: Id.Lit_Chars
                    val: '\t\ttest_when_finished "git reset --hard" &&\n'
                    span_id: 165
                  ) (Token id:Id.Lit_Chars val:'\t\tgit checkout --detach "$name^" &&\n' span_id:166) 
                  (Token
                    id: Id.Lit_Chars
                    val: '\t\tgit apply --index "$name.diff" &&\n'
                    span_id: 167
                  ) (Token id:Id.Lit_Chars val:'\t\tgit diff --exit-code "$name"\n' span_id:168) 
                  (Token id:Id.Lit_Chars val:'\t' span_id:169)
                )
              }
            )
          ]
        )
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:setup span_id:178))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:182) 
          (Token
            id: Id.Lit_Chars
            val: '\tcat "$dir/includes.c" "$dir/dummy.c" "$dir/dummy.c" "$dir/hello.c" \\\n'
            span_id: 183
          ) (Token id:Id.Lit_Chars val:'\t\t"$dir/dummy.c" "$dir/dummy.c" >file.c &&\n' span_id:184) 
          (Token id:Id.Lit_Chars val:'\tcommit_and_tag initial file.c &&\n' span_id:185) (Token id:Id.Lit_Chars val:'\n' span_id:186) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep -v "delete me from hello" <file.c >file.c.new &&\n'
            span_id: 187
          ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:188) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag changed_hello file.c &&\n'
            span_id: 189
          ) (Token id:Id.Lit_Chars val:'\n' span_id:190) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep -v "delete me from includes" <file.c >file.c.new &&\n'
            span_id: 191
          ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:192) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag changed_includes file.c &&\n'
            span_id: 193
          ) (Token id:Id.Lit_Chars val:'\n' span_id:194) 
          (Token id:Id.Lit_Chars val:'\tcat "$dir/appended1.c" >>file.c &&\n' span_id:195) (Token id:Id.Lit_Chars val:'\tcommit_and_tag appended file.c &&\n' span_id:196) 
          (Token id:Id.Lit_Chars val:'\n' span_id:197) (Token id:Id.Lit_Chars val:'\tcat "$dir/appended2.c" >>file.c &&\n' span_id:198) 
          (Token id:Id.Lit_Chars val:'\tcommit_and_tag extended file.c &&\n' span_id:199) (Token id:Id.Lit_Chars val:'\n' span_id:200) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep -v "Begin of second part" <file.c >file.c.new &&\n'
            span_id: 201
          ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:202) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag long_common_tail file.c &&\n'
            span_id: 203
          ) (Token id:Id.Lit_Chars val:'\n' span_id:204) 
          (Token id:Id.Lit_Chars val:'\tgit checkout initial &&\n' span_id:205) (Token id:Id.Lit_Chars val:'\tcat "$dir/hello.c" "$dir/dummy.c" >file.c &&\n' span_id:206) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag hello_dummy file.c &&\n'
            span_id: 207
          ) (Token id:Id.Lit_Chars val:'\n' span_id:208) 
          (Token
            id: Id.Lit_Chars
            val: '\t# overlap function context of 1st change and -u context of 2nd change\n'
            span_id: 209
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep -v "delete me from hello" <"$dir/hello.c" >file.c &&\n'
            span_id: 210
          ) (Token id:Id.Lit_Chars val:'\tsed 2p <"$dir/dummy.c" >>file.c &&\n' span_id:211) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag changed_hello_dummy file.c &&\n'
            span_id: 212
          ) (Token id:Id.Lit_Chars val:'\n' span_id:213) 
          (Token id:Id.Lit_Chars val:'\tgit checkout initial &&\n' span_id:214) (Token id:Id.Lit_Chars val:'\tgrep -v "delete me from hello" <file.c >file.c.new &&\n' span_id:215) 
          (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:216) (Token id:Id.Lit_Chars val:'\tcat "$dir/appended1.c" >>file.c &&\n' span_id:217) 
          (Token
            id: Id.Lit_Chars
            val: '\tcommit_and_tag changed_hello_appended file.c\n'
            span_id: 218
          )
        )
      }
    )
    (C {(check_diff)} {(changed_hello)} {(SQ (Token id:Id.Lit_Chars val:'changed function' span_id:227))})
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:234))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:238) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin of hello" changed_hello.diff\n'
            span_id: 239
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:246))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:250) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*End of hello" changed_hello.diff\n'
            span_id: 251
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:258))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:262) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" changed_hello.diff) -le 1\n'
            span_id: 263
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:270))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:274) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest "$(first_context_line <changed_hello.diff)" != " "\n'
            span_id: 275
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include trailing empty lines' span_id:282))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:286) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest "$(last_context_line <changed_hello.diff)" != " "\n'
            span_id: 287
          )
        )
      }
    )
    (C {(check_diff)} {(changed_includes)} 
      {(SQ (Token id:Id.Lit_Chars val:'changed includes' span_id:296))}
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:303))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:307) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin.h" changed_includes.diff\n'
            span_id: 308
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:315))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:319) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*End.h" changed_includes.diff\n'
            span_id: 320
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:327))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:331) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" changed_includes.diff) -le 1\n'
            span_id: 332
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include trailing empty lines' span_id:339))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:343) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest "$(last_context_line <changed_includes.diff)" != " "\n'
            span_id: 344
          )
        )
      }
    )
    (C {(check_diff)} {(appended)} {(SQ (Token id:Id.Lit_Chars val:'appended function' span_id:353))})
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:360))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:364) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^[+].*Begin of first part" appended.diff\n'
            span_id: 365
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:372))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:376) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^[+].*End of first part" appended.diff\n'
            span_id: 377
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:384))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:388) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" appended.diff) -le 1\n'
            span_id: 389
          )
        )
      }
    )
    (C {(check_diff)} {(extended)} 
      {(SQ (Token id:Id.Lit_Chars val:'appended function part' span_id:398))}
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:405))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:409) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin of first part" extended.diff\n'
            span_id: 410
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:417))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:421) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^[+].*End of second part" extended.diff\n'
            span_id: 422
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:429))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:433) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" extended.diff) -le 2\n'
            span_id: 434
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:441))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:445) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest "$(first_context_line <extended.diff)" != " "\n'
            span_id: 446
          )
        )
      }
    )
    (C {(check_diff)} {(long_common_tail)} 
      {(SQ (Token id:Id.Lit_Chars val:'change with long common tail and no context' span_id:455))} {(-U0)}
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:464))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:468) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin of first part" long_common_tail.diff\n'
            span_id: 469
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:476))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:480) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*End of second part" long_common_tail.diff\n'
            span_id: 481
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:488))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:492) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" long_common_tail.diff) -le 2\n'
            span_id: 493
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:500))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:504) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest "$(first_context_line <long_common_tail.diff.diff)" != " "\n'
            span_id: 505
          )
        )
      }
    )
    (C {(check_diff)} {(changed_hello_appended)} 
      {(SQ (Token id:Id.Lit_Chars val:'changed function plus appended function' span_id:514))}
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:521))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:525) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin of hello" changed_hello_appended.diff &&\n'
            span_id: 526
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^[+].*Begin of first part" changed_hello_appended.diff\n'
            span_id: 527
          )
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:534))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:538) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*End of hello" changed_hello_appended.diff &&\n'
            span_id: 539
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^[+].*End of first part" changed_hello_appended.diff\n'
            span_id: 540
          )
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:547))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:551) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^[ +-].*Begin" changed_hello_appended.diff) -le 2\n'
            span_id: 552
          )
        )
      }
    )
    (C {(check_diff)} {(changed_hello_dummy)} 
      {(SQ (Token id:Id.Lit_Chars val:'changed two consecutive functions' span_id:561))}
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:568))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:572) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*Begin of hello" changed_hello_dummy.diff &&\n'
            span_id: 573
          ) (Token id:Id.Lit_Chars val:'\tgrep "^ .*Begin of dummy" changed_hello_dummy.diff\n' span_id:574)
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:581))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:585) 
          (Token
            id: Id.Lit_Chars
            val: '\tgrep "^ .*End of hello" changed_hello_dummy.diff &&\n'
            span_id: 586
          ) (Token id:Id.Lit_Chars val:'\tgrep "^ .*End of dummy" changed_hello_dummy.diff\n' span_id:587)
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:' overlapping hunks are merged' span_id:594))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:598) 
          (Token
            id: Id.Lit_Chars
            val: '\ttest $(grep -c "^@@" changed_hello_dummy.diff) -eq 1\n'
            span_id: 599
          )
        )
      }
    )
    (C {(test_done)})
  ]
)