private static void rebaseMyGithubFork(
      @NotNull final Project project, @Nullable final VirtualFile file) {
    final GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
    if (gitRepository == null) {
      GithubNotifications.showError(
          project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find git repository");
      return;
    }

    BasicAction.saveAll();

    new Task.Backgroundable(project, "Rebasing GitHub fork...") {
      @Override
      public void run(@NotNull ProgressIndicator indicator) {
        gitRepository.update();
        String upstreamRemoteUrl = GithubUtil.findUpstreamRemote(gitRepository);

        if (upstreamRemoteUrl == null) {
          LOG.info("Configuring upstream remote");
          indicator.setText("Configuring upstream remote...");
          upstreamRemoteUrl = configureUpstreamRemote(project, gitRepository, indicator);
          if (upstreamRemoteUrl == null) {
            return;
          }
        }

        if (!GithubUrlUtil.isGithubUrl(upstreamRemoteUrl)) {
          GithubNotifications.showError(
              project,
              CANNOT_PERFORM_GITHUB_REBASE,
              "Configured upstream is not a GitHub repository: " + upstreamRemoteUrl);
          return;
        } else {
          final GithubFullPath userAndRepo =
              GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(upstreamRemoteUrl);
          final String login = GithubSettings.getInstance().getLogin();
          if (userAndRepo != null) {
            if (userAndRepo.getUser().equals(login)) {
              GithubNotifications.showError(
                  project,
                  CANNOT_PERFORM_GITHUB_REBASE,
                  "Configured upstream seems to be your own repository: " + upstreamRemoteUrl);
              return;
            }
          }
        }

        LOG.info("Fetching upstream");
        indicator.setText("Fetching upstream...");
        if (!fetchParent(project, gitRepository, indicator)) {
          return;
        }

        LOG.info("Rebasing current branch");
        indicator.setText("Rebasing current branch...");
        rebaseCurrentBranch(project, gitRepository, indicator);
      }
    }.queue();
  }
  @Override
  public void doCheckout(@NotNull final Project project, @Nullable final Listener listener) {
    if (!GerritUtil.testGitExecutable(project)) {
      return;
    }
    BasicAction.saveAll();
    List<ProjectInfo> availableProjects = null;
    try {
      availableProjects = GerritUtil.getAvailableProjects(project);
    } catch (IOException e) {
      LOG.info(e);
      GerritUtil.notifyError(
          project,
          "Couldn't get the list of Gerrit repositories",
          GerritUtil.getErrorTextFromException(e));
    }
    if (availableProjects == null) {
      return;
    }
    Collections.sort(
        availableProjects,
        new Comparator<ProjectInfo>() {
          @Override
          public int compare(final ProjectInfo p1, final ProjectInfo p2) {
            return p1.getId().compareTo(p2.getId());
          }
        });

    final GitCloneDialog dialog = new GitCloneDialog(project);
    // Add predefined repositories to history
    for (int i = availableProjects.size() - 1; i >= 0; i--) {
      dialog.prependToHistory(
          GerritSettings.getInstance().getHost() + '/' + availableProjects.get(i).getId());
    }
    dialog.show();
    if (!dialog.isOK()) {
      return;
    }
    dialog.rememberSettings();
    final VirtualFile destinationParent =
        LocalFileSystem.getInstance().findFileByIoFile(new File(dialog.getParentDirectory()));
    if (destinationParent == null) {
      return;
    }
    final String sourceRepositoryURL = dialog.getSourceRepositoryURL();
    final String directoryName = dialog.getDirectoryName();
    final String parentDirectory = dialog.getParentDirectory();

    Git git = ServiceManager.getService(Git.class);
    GitCheckoutProvider.clone(
        project,
        git,
        listener,
        destinationParent,
        sourceRepositoryURL,
        directoryName,
        parentDirectory);
  }
  /** Performs the actual sync/stash needed before attaching. */
  private void syncOrStash() {
    // When the user edits a document in intelliJ, there are spurious updates to the timestamp of
    // the document for an unspecified amount of time (even though there are no real edits).
    // So, we save-all right before we stash to (help) ensure we don't get a conflict dialog.
    // The conflict dialog happens when the timestamps of the document and file are mismatched.
    // So when we do the git operations, we want the document and file timestamps to match exactly.
    BasicAction.saveAll();

    mySourceRepository = mySyncResult.getLocalRepository();

    if (mySyncResult.needsStash() || mySyncResult.needsSync()) {
      if (mySourceRepository.getCurrentBranch() != null) {
        myOriginalBranchName = mySourceRepository.getCurrentBranch().getName();
      } else {
        myOriginalBranchName = mySourceRepository.getCurrentRevision();
      }
    }

    if (mySyncResult.needsStash()) {
      if (!stash()) {
        return;
      }
    }

    if (!Strings.isNullOrEmpty(mySyncResult.getTargetSyncSHA())) {
      // try to check out that revision.
      final GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
      if (mySourceRepository == null) {
        LOG.error("unexpected null source repo with a target SHA.");
        return;
      }
      assert mySyncResult.getTargetSyncSHA() != null;
      brancher.checkout(
          mySyncResult.getTargetSyncSHA(),
          Collections.singletonList(mySourceRepository),
          new Runnable() {
            @Override
            public void run() {
              refreshAndClose();
            }
          });
    } else {
      refreshAndClose();
    }
  }
  @Override
  public void doCheckout(@NotNull final Project project, @Nullable final Listener listener) {
    if (!GithubUtil.testGitExecutable(project)) {
      return;
    }
    BasicAction.saveAll();

    List<GithubRepo> availableRepos;
    try {
      availableRepos =
          GithubUtil.computeValueInModal(
              project,
              "Access to GitHub",
              new ThrowableConvertor<ProgressIndicator, List<GithubRepo>, IOException>() {
                @NotNull
                @Override
                public List<GithubRepo> convert(ProgressIndicator indicator) throws IOException {
                  return GithubUtil.runTask(
                      project,
                      GithubAuthDataHolder.createFromSettings(),
                      indicator,
                      new ThrowableConvertor<GithubAuthData, List<GithubRepo>, IOException>() {
                        @NotNull
                        @Override
                        public List<GithubRepo> convert(@NotNull GithubAuthData auth)
                            throws IOException {
                          return GithubApiUtil.getAvailableRepos(auth);
                        }
                      });
                }
              });
    } catch (IOException e) {
      GithubNotifications.showError(project, "Couldn't get the list of GitHub repositories", e);
      return;
    }
    Collections.sort(
        availableRepos,
        new Comparator<GithubRepo>() {
          @Override
          public int compare(final GithubRepo r1, final GithubRepo r2) {
            final int comparedOwners = r1.getUserName().compareTo(r2.getUserName());
            return comparedOwners != 0 ? comparedOwners : r1.getName().compareTo(r2.getName());
          }
        });

    final GitCloneDialog dialog = new GitCloneDialog(project);
    // Add predefined repositories to history
    dialog.prependToHistory("-----------------------------------------------");
    for (int i = availableRepos.size() - 1; i >= 0; i--) {
      dialog.prependToHistory(availableRepos.get(i).getCloneUrl());
    }
    dialog.show();
    if (!dialog.isOK()) {
      return;
    }
    dialog.rememberSettings();
    final VirtualFile destinationParent =
        LocalFileSystem.getInstance().findFileByIoFile(new File(dialog.getParentDirectory()));
    if (destinationParent == null) {
      return;
    }
    final String sourceRepositoryURL = dialog.getSourceRepositoryURL();
    final String directoryName = dialog.getDirectoryName();
    final String parentDirectory = dialog.getParentDirectory();

    Git git = ServiceManager.getService(Git.class);
    GitCheckoutProvider.clone(
        project,
        git,
        listener,
        destinationParent,
        sourceRepositoryURL,
        directoryName,
        parentDirectory);
  }
  public static void shareProjectOnGithub(
      @NotNull final Project project, @Nullable final VirtualFile file) {
    BasicAction.saveAll();

    // get gitRepository
    final GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
    final boolean gitDetected = gitRepository != null;
    final VirtualFile root = gitDetected ? gitRepository.getRoot() : project.getBaseDir();

    // check for existing git repo
    boolean externalRemoteDetected = false;
    if (gitDetected) {
      final String githubRemote = GithubUtil.findGithubRemoteUrl(gitRepository);
      if (githubRemote != null) {
        GithubNotifications.showInfoURL(
            project, "Project is already on GitHub", "GitHub", githubRemote);
        return;
      }
      externalRemoteDetected = !gitRepository.getRemotes().isEmpty();
    }

    final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings();

    // get available GitHub repos with modal progress
    final GithubInfo githubInfo = loadGithubInfoWithModal(authHolder, project);
    if (githubInfo == null) {
      return;
    }

    // Show dialog (window)
    final GithubShareDialog shareDialog =
        new GithubShareDialog(
            project, githubInfo.getRepositoryNames(), githubInfo.getUser().canCreatePrivateRepo());
    DialogManager.show(shareDialog);
    if (!shareDialog.isOK()) {
      return;
    }
    final boolean isPrivate = shareDialog.isPrivate();
    final String name = shareDialog.getRepositoryName();
    final String description = shareDialog.getDescription();

    // finish the job in background
    final boolean finalExternalRemoteDetected = externalRemoteDetected;
    new Task.Backgroundable(project, "Sharing project on GitHub...") {
      @Override
      public void run(@NotNull ProgressIndicator indicator) {
        // create GitHub repo (network)
        LOG.info("Creating GitHub repository");
        indicator.setText("Creating GitHub repository...");
        final String url =
            createGithubRepository(project, authHolder, indicator, name, description, isPrivate);
        if (url == null) {
          return;
        }
        LOG.info("Successfully created GitHub repository");

        // creating empty git repo if git is not initialized
        LOG.info("Binding local project with GitHub");
        if (!gitDetected) {
          LOG.info("No git detected, creating empty git repo");
          indicator.setText("Creating empty git repo...");
          if (!createEmptyGitRepository(project, root, indicator)) {
            return;
          }
        }

        GitRepositoryManager repositoryManager = GitUtil.getRepositoryManager(project);
        final GitRepository repository = repositoryManager.getRepositoryForRoot(root);
        LOG.assertTrue(repository != null, "GitRepository is null for root " + root);
        if (repository == null) {
          GithubNotifications.showError(
              project, "Failed to create GitHub Repository", "Can't find Git repository");
          return;
        }

        final String remoteUrl = GithubUrlUtil.getCloneUrl(githubInfo.getUser().getLogin(), name);
        final String remoteName = finalExternalRemoteDetected ? "github" : "origin";

        // git remote add origin [email protected]:login/name.git
        LOG.info("Adding GitHub as a remote host");
        indicator.setText("Adding GitHub as a remote host...");
        if (!GithubUtil.addGithubRemote(project, repository, remoteName, remoteUrl)) {
          return;
        }

        // create sample commit for binding project
        if (!performFirstCommitIfRequired(project, root, repository, indicator, name, url)) {
          return;
        }

        // git push origin master
        LOG.info("Pushing to github master");
        indicator.setText("Pushing to github master...");
        if (!pushCurrentBranch(project, repository, remoteName, remoteUrl, name, url)) {
          return;
        }

        GithubNotifications.showInfoURL(
            project, "Successfully shared project on GitHub", name, url);
      }
    }.queue();
  }
  public CloudAttachDialog(@NotNull Project project) {
    super(project, true);

    myProject = project;
    init();
    initValidation();
    setTitle(GctBundle.getString("clouddebug.attachtitle"));
    setOKButtonText(GctBundle.getString("clouddebug.attach"));
    mySyncStashCheckbox.setVisible(false);
    mySyncStashCheckbox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            if (mySyncStashCheckbox.isVisible()) {
              myWarningLabel.setVisible(!mySyncStashCheckbox.isSelected());
              myWarningLabel2.setVisible(!mySyncStashCheckbox.isSelected());
              myInfoPanel.setVisible(mySyncStashCheckbox.isSelected());
              if (mySyncStashCheckbox.isSelected()) {
                setOKButtonText(
                    isContinued()
                        ? GctBundle.getString("clouddebug.continuesession")
                        : GctBundle.getString("clouddebug.attach"));
              } else {
                setOKButtonText(
                    isContinued()
                        ? GctBundle.getString("clouddebug.continueanyway")
                        : GctBundle.getString("clouddebug.attach.anyway"));
              }
            }
          }
        });

    myWarningLabel.setVisible(false);
    myWarningLabel.setFont(
        new Font(
            myWarningLabel.getFont().getName(), Font.BOLD, myWarningLabel.getFont().getSize() - 1));
    myWarningLabel.setForeground(JBColor.RED);
    myWarningLabel2.setVisible(false);
    myWarningLabel2.setFont(
        new Font(
            myWarningLabel2.getFont().getName(),
            Font.PLAIN,
            myWarningLabel.getFont().getSize() - 1));
    myWarningLabel2.setText(GctBundle.getString("clouddebug.sourcedoesnotmatch"));

    myInfoPanel.setFont(
        new Font(
            myWarningLabel2.getFont().getName(),
            Font.PLAIN,
            myWarningLabel.getFont().getSize() - 1));
    Border paddingBorder = BorderFactory.createEmptyBorder(2, 0, 2, 0);
    myInfoPanel.setBorder(paddingBorder);

    Window myWindow = getWindow();
    if (myWindow != null) {
      myWindow.setPreferredSize(new Dimension(355, 175));
    }
    BasicAction.saveAll();

    myWireup = new ProjectDebuggeeBinding(myElysiumProjectId, myDebuggeeTarget);
    myDebuggeeTarget.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            buildResult();
            checkSyncStashState();
            setOKActionEnabled(doValidate() == null);
          }
        });

    setOKActionEnabled(isContinued() || doValidate() == null);
  }