async prepare(ctx, task) {
    try {
      debugLog(task.title)

      // Get a list of files with both staged and unstaged changes.
      // Unstaged changes to these files should be hidden before the tasks run.
      this.partiallyStagedFiles = await this.getPartiallyStagedFiles()

      if (this.partiallyStagedFiles) {
        ctx.hasPartiallyStagedFiles = true
        const unstagedPatch = this.getHiddenFilepath(PATCH_UNSTAGED)
        const files = processRenames(this.partiallyStagedFiles)
        await this.execGit(['diff', ...GIT_DIFF_ARGS, '--output', unstagedPatch, '--', ...files])
      } else {
        ctx.hasPartiallyStagedFiles = false
      }

      /**
       * If backup stash should be skipped, no need to continue
       */
      if (!ctx.shouldBackup) return

      // When backup is enabled, the revert will clear ongoing merge status.
      await this.backupMergeStatus()

      // Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
      // - in git versions =< 2.13.0 the `git stash --keep-index` option resurrects deleted files
      // - git stash can't infer RD or MD states correctly, and will lose the deletion
      this.deletedFiles = await this.getDeletedFiles()

      // Save stash of all staged files.
      // The `stash create` command creates a dangling commit without removing any files,
      // and `stash store` saves it as an actual stash.
      const stashHash = await this.execGit(['stash', 'create'])
      ctx.backupHash = await this.execGit(['rev-parse', '--short', stashHash])
      await this.execGit([
        'stash',
        'store',
        '--quiet',
        '--message',
        `${STASH} (${ctx.backupHash})`,
        ctx.backupHash,
      ])

      task.title = `Backed up original state in git stash (${ctx.backupHash})`
      debugLog(task.title)
    } catch (error) {
      handleError(error, ctx)
    }
  }
Create a diff of partially staged files and backup stash if enabled.