(CommandList
  children: [
    (Assignment
      keyword: Assign_None
      pairs: [
        (assign_pair
          lhs: (LhsName name:test_description)
          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">
              )
            }
          spids: [4]
        )
      ]
      spids: [4]
    )
    (C {(.)} {(./test-lib.sh)})
    (C {(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">
        )
      }
    )
    (Assignment
      keyword: Assign_None
      pairs: [
        (assign_pair
          lhs: (LhsName name:pre_merge_head)
          op: Equal
          rhs: 
            {
              (DQ 
                (CommandSubPart
                  command_list: (CommandList children:[(C {(git)} {(rev-parse)} {(HEAD)})])
                  left_token: <Left_CommandSub "$(">
                  spids: [63 69]
                )
              )
            }
          spids: [61]
        )
      ]
      spids: [61]
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Forget previous merge">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} 
      {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)}
    )
    (C {(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">
        )
      }
    )
    (C {(test_done)})
  ]
)