(command.CommandList
  children: [
    (command.ShAssignment
      left: <Id.Lit_VarLike 'test_description='>
      pairs: [
        (AssignPair
          left: <Id.Lit_VarLike 'test_description='>
          lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'test_description='> name:test_description)
          op: assign_op.Equal
          rhs: 
            {
              (SQ <'test aborting in-progress merges\n'> <'\n'> 
                <'Set up repo with conflicting and non-conflicting branches:\n'> <'\n'> <'There are three files foo/bar/baz, and the following graph illustrates the\n'> 
                <'content of these files in each commit:\n'> <'\n'> <'# foo/bar/baz --- foo/bar/bazz     <-- master\n'> <'#             \\\n'> 
                <'#              --- foo/barf/bazf   <-- conflict_branch\n'> <'#               \\\n'> <'#                --- foo/bart/baz  <-- clean_branch\n'> <'\n'> 
                <'Next, test git merge --abort with the following variables:\n'> <'- before/after successful merge (should fail when not in merge context)\n'> 
                <'- with/without conflicts\n'> <'- clean/dirty index before merge\n'> <'- clean/dirty worktree before merge\n'> 
                <'- dirty index before merge matches contents on remote branch\n'> <'- changed/unchanged worktree after merge\n'> <'- changed/unchanged index after merge\n'>
              )
            }
        )
      ]
      redirects: []
    )
    (command.Simple
      blame_tok: <.>
      more_env: []
      words: [{<.>} {<'./test-lib.sh'>}]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <setup>)}
        {
          (SQ <'\n'> <'\t# Create the above repo\n'> <'\techo foo > foo &&\n'> <'\techo bar > bar &&\n'> 
            <'\techo baz > baz &&\n'> <'\tgit add foo bar baz &&\n'> <'\tgit commit -m initial &&\n'> <'\techo bazz > baz &&\n'> 
            <'\tgit commit -a -m "second" &&\n'> <'\tgit checkout -b conflict_branch HEAD^ &&\n'> <'\techo barf > bar &&\n'> <'\techo bazf > baz &&\n'> 
            <'\tgit commit -a -m "conflict" &&\n'> <'\tgit checkout -b clean_branch HEAD^ &&\n'> <'\techo bart > bar &&\n'> 
            <'\tgit commit -a -m "clean" &&\n'> <'\tgit checkout master\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.ShAssignment
      left: <Id.Lit_VarLike 'pre_merge_head='>
      pairs: [
        (AssignPair
          left: <Id.Lit_VarLike 'pre_merge_head='>
          lhs: (sh_lhs_expr.Name left:<Id.Lit_VarLike 'pre_merge_head='> name:pre_merge_head)
          op: assign_op.Equal
          rhs: 
            {
              (DQ 
                (CommandSub
                  left_token: <Id.Left_DollarParen '$('>
                  child: 
                    (command.Simple
                      blame_tok: <git>
                      more_env: []
                      words: [{<git>} {<rev-parse>} {<HEAD>}]
                      redirects: []
                      do_fork: T
                    )
                  right: <Id.Eof_RParen _>
                )
              )
            }
        )
      ]
      redirects: []
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'fails without MERGE_HEAD (unstarted merge)'>)}
        {
          (SQ <'\n'> <'\ttest_must_fail git merge --abort 2>output &&\n'> 
            <'\ttest_i18ngrep MERGE_HEAD output\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity'>)}
        {
          (SQ <'\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'fails without MERGE_HEAD (completed merge)'>)}
        {
          (SQ <'\n'> <'\tgit merge clean_branch &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\t# Merge successfully completed\n'> <'\tpost_merge_head="$(git rev-parse HEAD)" &&\n'> 
            <'\ttest_must_fail git merge --abort 2>output &&\n'> <'\ttest_i18ngrep MERGE_HEAD output\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity'>)}
        {
          (SQ <'\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$post_merge_head" = "$(git rev-parse HEAD)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Forget previous merge'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort after --no-commit'>)}
        {
          (SQ <'\n'> <'\t# Redo merge, but stop before creating merge commit\n'> 
            <'\tgit merge --no-commit clean_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> <'\t# Abort non-conflicting merge\n'> <'\tgit merge --abort &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff)" &&\n'> 
            <'\ttest -z "$(git diff --staged)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort after conflicts'>)}
        {
          (SQ <'\n'> <'\t# Create conflicting merge\n'> 
            <'\ttest_must_fail git merge conflict_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> <'\t# Abort conflicting merge\n'> <'\tgit merge --abort &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff)" &&\n'> 
            <'\ttest -z "$(git diff --staged)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Clean merge with dirty index fails'>)}
        {
          (SQ <'\n'> <'\techo xyzzy >> foo &&\n'> <'\tgit add foo &&\n'> 
            <'\tgit diff --staged > expect &&\n'> <'\ttest_must_fail git merge clean_branch &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff)" &&\n'> <'\tgit diff --staged > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Conflicting merge with dirty index fails'>)}
        {
          (SQ <'\n'> <'\ttest_must_fail git merge conflict_branch &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff)" &&\n'> 
            <'\tgit diff --staged > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset index (but preserve worktree changes)'>)}
        {
          (SQ <'\n'> <'\tgit reset "$pre_merge_head" &&\n'> <'\tgit diff > actual &&\n'> 
            <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort clean merge with non-conflicting dirty worktree'>)}
        {
          (SQ <'\n'> <'\tgit merge --no-commit clean_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> 
            <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff --staged)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort conflicting merge with non-conflicting dirty worktree'>)}
        {
          (SQ <'\n'> <'\ttest_must_fail git merge conflict_branch &&\n'> 
            <'\ttest -f .git/MERGE_HEAD &&\n'> <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff --staged)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset worktree changes'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Fail clean merge with conflicting dirty worktree'>)}
        {
          (SQ <'\n'> <'\techo xyzzy >> bar &&\n'> <'\tgit diff > expect &&\n'> 
            <'\ttest_must_fail git merge --no-commit clean_branch &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> 
            <'\ttest -z "$(git diff --staged)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Fail conflicting merge with conflicting dirty worktree'>)}
        {
          (SQ <'\n'> <'\ttest_must_fail git merge conflict_branch &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\ttest -z "$(git diff --staged)" &&\n'> 
            <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset worktree changes'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Fail clean merge with matching dirty worktree'>)}
        {
          (SQ <'\n'> <'\techo bart > bar &&\n'> <'\tgit diff > expect &&\n'> 
            <'\ttest_must_fail git merge --no-commit clean_branch &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> 
            <'\ttest -z "$(git diff --staged)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort clean merge with matching dirty index'>)}
        {
          (SQ <'\n'> <'\tgit add bar &&\n'> <'\tgit diff --staged > expect &&\n'> 
            <'\tgit merge --no-commit clean_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> 
            <'\t### When aborting the merge, git will discard all staged changes,\n'> <'\t### including those that were staged pre-merge. In other words,\n'> 
            <'\t### --abort will LOSE any staged changes (the staged changes that\n'> <'\t### are lost must match the merge result, or the merge would not\n'> 
            <'\t### have been allowed to start). Change expectations accordingly:\n'> <'\trm expect &&\n'> <'\ttouch expect &&\n'> <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\tgit diff --staged > actual &&\n'> 
            <'\ttest_cmp expect actual &&\n'> <'\ttest -z "$(git diff)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset worktree changes'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Fail conflicting merge with matching dirty worktree'>)}
        {
          (SQ <'\n'> <'\techo barf > bar &&\n'> <'\tgit diff > expect &&\n'> 
            <'\ttest_must_fail git merge conflict_branch &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> 
            <'\ttest -z "$(git diff --staged)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort conflicting merge with matching dirty index'>)}
        {
          (SQ <'\n'> <'\tgit add bar &&\n'> <'\tgit diff --staged > expect &&\n'> 
            <'\ttest_must_fail git merge conflict_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> 
            <'\t### When aborting the merge, git will discard all staged changes,\n'> <'\t### including those that were staged pre-merge. In other words,\n'> 
            <'\t### --abort will LOSE any staged changes (the staged changes that\n'> <'\t### are lost must match the merge result, or the merge would not\n'> 
            <'\t### have been allowed to start). Change expectations accordingly:\n'> <'\trm expect &&\n'> <'\ttouch expect &&\n'> <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\tgit diff --staged > actual &&\n'> 
            <'\ttest_cmp expect actual &&\n'> <'\ttest -z "$(git diff)"\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset worktree changes'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort merge with pre- and post-merge worktree changes'>)}
        {
          (SQ <'\n'> <'\t# Pre-merge worktree changes\n'> <'\techo xyzzy > foo &&\n'> 
            <'\techo barf > bar &&\n'> <'\tgit add bar &&\n'> <'\tgit diff > expect &&\n'> <'\tgit diff --staged > expect-staged &&\n'> 
            <'\t# Perform merge\n'> <'\ttest_must_fail git merge conflict_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> 
            <'\t# Post-merge worktree changes\n'> <'\techo yzxxz > foo &&\n'> <'\techo blech > baz &&\n'> 
            <'\t### When aborting the merge, git will discard staged changes (bar)\n'> <'\t### and unmerged changes (baz). Other changes that are neither\n'> 
            <'\t### staged nor marked as unmerged (foo), will be preserved. For\n'> <'\t### these changed, git cannot tell pre-merge changes apart from\n'> 
            <'\t### post-merge changes, so the post-merge changes will be\n'> <'\t### preserved. Change expectations accordingly:\n'> <'\tgit diff -- foo > expect &&\n'> 
            <'\trm expect-staged &&\n'> <'\ttouch expect-staged &&\n'> <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> 
            <'\ttest ! -f .git/MERGE_HEAD &&\n'> <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\tgit diff > actual &&\n'> 
            <'\ttest_cmp expect actual &&\n'> <'\tgit diff --staged > actual-staged &&\n'> <'\ttest_cmp expect-staged actual-staged\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Reset worktree changes'>)}
        {(SQ <'\n'> <'\tgit reset --hard "$pre_merge_head"\n'>)}
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_expect_success>
      more_env: []
      words: [
        {<test_expect_success>}
        {(SQ <'Abort merge with pre- and post-merge index changes'>)}
        {
          (SQ <'\n'> <'\t# Pre-merge worktree changes\n'> <'\techo xyzzy > foo &&\n'> 
            <'\techo barf > bar &&\n'> <'\tgit add bar &&\n'> <'\tgit diff > expect &&\n'> <'\tgit diff --staged > expect-staged &&\n'> 
            <'\t# Perform merge\n'> <'\ttest_must_fail git merge conflict_branch &&\n'> <'\ttest -f .git/MERGE_HEAD &&\n'> 
            <'\t# Post-merge worktree changes\n'> <'\techo yzxxz > foo &&\n'> <'\techo blech > baz &&\n'> <'\tgit add foo bar &&\n'> 
            <'\t### When aborting the merge, git will discard all staged changes\n'> <'\t### (foo, bar and baz), and no changes will be preserved. Whether\n'> 
            <'\t### the changes were staged pre- or post-merge does not matter\n'> <'\t### (except for not preventing starting the merge).\n'> 
            <'\t### Change expectations accordingly:\n'> <'\trm expect expect-staged &&\n'> <'\ttouch expect &&\n'> <'\ttouch expect-staged &&\n'> 
            <'\t# Abort merge\n'> <'\tgit merge --abort &&\n'> <'\ttest ! -f .git/MERGE_HEAD &&\n'> 
            <'\ttest "$pre_merge_head" = "$(git rev-parse HEAD)" &&\n'> <'\tgit diff > actual &&\n'> <'\ttest_cmp expect actual &&\n'> 
            <'\tgit diff --staged > actual-staged &&\n'> <'\ttest_cmp expect-staged actual-staged\n'>
          )
        }
      ]
      redirects: []
      do_fork: T
    )
    (command.Simple
      blame_tok: <test_done>
      more_env: []
      words: [{<test_done>}]
      redirects: []
      do_fork: T
    )
  ]
)