@Override
    public void apply(
        @NotNull MultiMap<VirtualFile, TextFilePatchInProgress> patchGroups,
        @Nullable LocalChangeList localList,
        @Nullable String fileName,
        @Nullable
            TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException>
                additionalInfo) {
      final List<FilePatch> patches;
      try {
        patches = ApplyPatchSaveToFileExecutor.patchGroupsToOneGroup(patchGroups, myBaseDir);
      } catch (IOException e) {
        myInner.handleException(e, true);
        return;
      }

      final PatchApplier<BinaryFilePatch> patchApplier =
          new PatchApplier<BinaryFilePatch>(
              myVcs.getProject(), myBaseDir, patches, localList, null, null);
      patchApplier.execute(false, true); // 3
      boolean thereAreCreations = false;
      for (FilePatch patch : patches) {
        if (patch.isNewFile() || !Comparing.equal(patch.getAfterName(), patch.getBeforeName())) {
          thereAreCreations = true;
          break;
        }
      }
      if (thereAreCreations) {
        // restore deletion of old directory:
        myInner.next(new DirectoryAddition()); // 2
      }
      appendResolveConflictToContext(myInner); // 1
      appendTailToContextLast(myInner); // 4
      myInner.ping();
    }
 private void removeAppliedAndSaveRemainedIfNeeded(
     @NotNull Collection<PatchApplier> appliers, @NotNull CommitContext commitContext) {
   ShelveChangesManager shelveChangesManager = ShelveChangesManager.getInstance(myProject);
   if (!shelveChangesManager.isRemoveFilesFromShelf()) return;
   try {
     List<FilePatch> textPatches =
         ContainerUtil.<FilePatch>newArrayList(
             ShelveChangesManager.loadPatches(
                 myProject, myCurrentShelveChangeList.PATH, commitContext));
     List<FilePatch> remainingBinaries =
         ContainerUtil.<FilePatch>newArrayList(myBinaryShelvedPatches);
     for (PatchApplier applier : appliers) {
       textPatches.removeAll(applier.getPatches());
       textPatches.addAll(applier.getRemainingPatches());
       remainingBinaries.removeAll(applier.getBinaryPatches());
     }
     if (textPatches.isEmpty() && remainingBinaries.isEmpty()) {
       shelveChangesManager.recycleChangeList(myCurrentShelveChangeList);
     } else {
       shelveChangesManager.saveRemainingPatches(
           myCurrentShelveChangeList,
           textPatches,
           ContainerUtil.mapNotNull(
               remainingBinaries,
               new Function<FilePatch, ShelvedBinaryFile>() {
                 @Override
                 public ShelvedBinaryFile fun(FilePatch patch) {
                   return patch instanceof ShelvedBinaryFilePatch
                       ? ((ShelvedBinaryFilePatch) patch).getShelvedBinaryFile()
                       : null;
                 }
               }),
           commitContext);
     }
   } catch (Exception e) {
     LOG.error("Couldn't update and store remaining patches", e);
   }
 }
  @CalledInAwt
  public static ApplyPatchStatus executePatchGroup(
      final Collection<PatchApplier> group, final LocalChangeList localChangeList) {
    if (group.isEmpty()) return ApplyPatchStatus.SUCCESS; // ?
    final Project project = group.iterator().next().myProject;

    ApplyPatchStatus result = ApplyPatchStatus.SUCCESS;
    for (PatchApplier patchApplier : group) {
      result = ApplyPatchStatus.and(result, patchApplier.nonWriteActionPreCheck());
    }
    final Label beforeLabel = LocalHistory.getInstance().putSystemLabel(project, "Before patch");
    final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(project);
    final Ref<ApplyPatchStatus> refStatus = new Ref<>(result);
    try {
      CommandProcessor.getInstance()
          .executeCommand(
              project,
              new Runnable() {
                @Override
                public void run() {
                  for (PatchApplier applier : group) {
                    refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.createFiles()));
                    applier.addSkippedItems(trigger);
                  }
                  trigger.prepare();
                  if (refStatus.get() == ApplyPatchStatus.SUCCESS) {
                    // all pre-check results are valuable only if not successful; actual status we
                    // can receive after executeWritable
                    refStatus.set(null);
                  }
                  for (PatchApplier applier : group) {
                    refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.executeWritable()));
                    if (refStatus.get() == ApplyPatchStatus.ABORT) break;
                  }
                }
              },
              VcsBundle.message("patch.apply.command"),
              null);
    } finally {
      VcsFileListenerContextHelper.getInstance(project).clearContext();
      LocalHistory.getInstance().putSystemLabel(project, "After patch");
    }
    result = refStatus.get();
    result = result == null ? ApplyPatchStatus.FAILURE : result;

    trigger.processIt();
    final Set<FilePath> directlyAffected = new HashSet<>();
    final Set<VirtualFile> indirectlyAffected = new HashSet<>();
    for (PatchApplier applier : group) {
      directlyAffected.addAll(applier.getDirectlyAffected());
      indirectlyAffected.addAll(applier.getIndirectlyAffected());
    }
    directlyAffected.addAll(trigger.getAffected());
    final Consumer<Collection<FilePath>> mover =
        localChangeList == null ? null : createMover(project, localChangeList);
    refreshPassedFilesAndMoveToChangelist(project, directlyAffected, indirectlyAffected, mover);
    if (result == ApplyPatchStatus.FAILURE) {
      suggestRollback(project, group, beforeLabel);
    } else if (result == ApplyPatchStatus.ABORT) {
      rollbackUnderProgress(project, project.getBaseDir(), beforeLabel);
    }
    showApplyStatus(project, result);
    return result;
  }