private static boolean pushCurrentBranch(
      @NotNull Project project,
      @NotNull GitRepository repository,
      @NotNull String remoteName,
      @NotNull String remoteUrl,
      @NotNull String name,
      @NotNull String url) {
    Git git = ServiceManager.getService(Git.class);

    GitLocalBranch currentBranch = repository.getCurrentBranch();
    if (currentBranch == null) {
      GithubNotifications.showErrorURL(
          project,
          "Can't finish GitHub sharing process",
          "Successfully created project ",
          "'" + name + "'",
          " on GitHub, but initial push failed: no current branch",
          url);
      return false;
    }
    GitCommandResult result =
        git.push(repository, remoteName, remoteUrl, currentBranch.getName(), true);
    if (!result.success()) {
      GithubNotifications.showErrorURL(
          project,
          "Can't finish GitHub sharing process",
          "Successfully created project ",
          "'" + name + "'",
          " on GitHub, but initial push failed:<br/>" + result.getErrorOutputAsHtmlString(),
          url);
      return false;
    }
    return true;
  }
  @Nullable
  static String configureUpstreamRemote(
      @NotNull Project project,
      @NotNull GitRepository gitRepository,
      @NotNull ProgressIndicator indicator) {
    GithubRepoDetailed repositoryInfo = loadRepositoryInfo(project, gitRepository, indicator);
    if (repositoryInfo == null) {
      return null;
    }

    if (!repositoryInfo.isFork() || repositoryInfo.getParent() == null) {
      GithubNotifications.showWarningURL(
          project,
          CANNOT_PERFORM_GITHUB_REBASE,
          "GitHub repository ",
          "'" + repositoryInfo.getName() + "'",
          " is not a forked one",
          repositoryInfo.getHtmlUrl());
      return null;
    }

    final String parentRepoUrl =
        GithubUrlUtil.getCloneUrl(repositoryInfo.getParent().getFullPath());

    LOG.info("Adding GitHub parent as a remote host");
    indicator.setText("Adding GitHub parent as a remote host...");

    if (GithubUtil.addGithubRemote(project, gitRepository, "upstream", parentRepoUrl)) {
      return parentRepoUrl;
    } else {
      return null;
    }
  }
  @Nullable
  private static String createGithubRepository(
      @NotNull Project project,
      @NotNull GithubAuthDataHolder authHolder,
      @NotNull ProgressIndicator indicator,
      @NotNull final String name,
      @NotNull final String description,
      final boolean isPrivate) {

    try {
      return GithubUtil.runTask(
              project,
              authHolder,
              indicator,
              new ThrowableConvertor<GithubAuthData, GithubRepo, IOException>() {
                @NotNull
                @Override
                public GithubRepo convert(@NotNull GithubAuthData auth) throws IOException {
                  return GithubApiUtil.createRepo(auth, name, description, isPrivate);
                }
              })
          .getHtmlUrl();
    } catch (IOException e) {
      GithubNotifications.showError(project, "Failed to create GitHub Repository", e);
      return null;
    }
  }
  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();
  }
  @Nullable
  private static GithubRepoDetailed loadRepositoryInfo(
      @NotNull Project project,
      @NotNull GitRepository gitRepository,
      @NotNull ProgressIndicator indicator) {
    final String remoteUrl = GithubUtil.findGithubRemoteUrl(gitRepository);
    if (remoteUrl == null) {
      GithubNotifications.showError(
          project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find github remote");
      return null;
    }
    final GithubFullPath userAndRepo = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
    if (userAndRepo == null) {
      GithubNotifications.showError(
          project, CANNOT_PERFORM_GITHUB_REBASE, "Can't process remote: " + remoteUrl);
      return null;
    }

    try {
      return GithubUtil.runWithValidAuth(
          project,
          indicator,
          new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() {
            @Override
            @NotNull
            public GithubRepoDetailed convert(GithubAuthData authData) throws IOException {
              return GithubApiUtil.getDetailedRepoInfo(
                  authData, userAndRepo.getUser(), userAndRepo.getRepository());
            }
          });
    } catch (GithubOperationCanceledException e) {
      return null;
    } catch (IOException e) {
      GithubNotifications.showError(project, "Can't load repository info", e);
      return null;
    }
  }
  @Nullable
  private static GithubInfo loadGithubInfoWithModal(
      @NotNull final GithubAuthDataHolder authHolder, @NotNull final Project project) {
    try {
      return GithubUtil.computeValueInModal(
          project,
          "Access to GitHub",
          new ThrowableConvertor<ProgressIndicator, GithubInfo, IOException>() {
            @NotNull
            @Override
            public GithubInfo convert(ProgressIndicator indicator) throws IOException {
              // get existing github repos (network) and validate auth data
              return GithubUtil.runTask(
                  project,
                  authHolder,
                  indicator,
                  new ThrowableConvertor<GithubAuthData, GithubInfo, IOException>() {
                    @NotNull
                    @Override
                    public GithubInfo convert(@NotNull GithubAuthData auth) throws IOException {
                      // check access to private repos (network)
                      GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth);

                      HashSet<String> names = new HashSet<String>();
                      for (GithubRepo info : GithubApiUtil.getUserRepos(auth)) {
                        names.add(info.getName());
                      }
                      return new GithubInfo(userInfo, names);
                    }
                  });
            }
          });
    } catch (GithubOperationCanceledException e) {
      return null;
    } catch (IOException e) {
      GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", e);
      return null;
    }
  }
  private static boolean performFirstCommitIfRequired(
      @NotNull final Project project,
      @NotNull VirtualFile root,
      @NotNull GitRepository repository,
      @NotNull ProgressIndicator indicator,
      @NotNull String name,
      @NotNull String url) {
    // check if there is no commits
    if (!repository.isFresh()) {
      return true;
    }

    LOG.info("Trying to commit");
    try {
      LOG.info("Adding files for commit");
      indicator.setText("Adding files to git...");

      // ask for files to add
      final List<VirtualFile> trackedFiles =
          ChangeListManager.getInstance(project).getAffectedFiles();
      final Collection<VirtualFile> untrackedFiles =
          filterOutIgnored(project, repository.getUntrackedFilesHolder().retrieveUntrackedFiles());
      trackedFiles.removeAll(untrackedFiles); // fix IDEA-119855

      final List<VirtualFile> allFiles = new ArrayList<VirtualFile>();
      allFiles.addAll(trackedFiles);
      allFiles.addAll(untrackedFiles);

      final Ref<GithubUntrackedFilesDialog> dialogRef = new Ref<GithubUntrackedFilesDialog>();
      ApplicationManager.getApplication()
          .invokeAndWait(
              new Runnable() {
                @Override
                public void run() {
                  GithubUntrackedFilesDialog dialog =
                      new GithubUntrackedFilesDialog(project, allFiles);
                  if (!trackedFiles.isEmpty()) {
                    dialog.setSelectedFiles(trackedFiles);
                  }
                  DialogManager.show(dialog);
                  dialogRef.set(dialog);
                }
              },
              indicator.getModalityState());
      final GithubUntrackedFilesDialog dialog = dialogRef.get();

      final Collection<VirtualFile> files2commit = dialog.getSelectedFiles();
      if (!dialog.isOK() || files2commit.isEmpty()) {
        GithubNotifications.showInfoURL(
            project, "Successfully created empty repository on GitHub", name, url);
        return false;
      }

      Collection<VirtualFile> files2add = ContainerUtil.intersection(untrackedFiles, files2commit);
      Collection<VirtualFile> files2rm = ContainerUtil.subtract(trackedFiles, files2commit);
      Collection<VirtualFile> modified = new HashSet<VirtualFile>(trackedFiles);
      modified.addAll(files2commit);

      GitFileUtils.addFiles(project, root, files2add);
      GitFileUtils.deleteFilesFromCache(project, root, files2rm);

      // commit
      LOG.info("Performing commit");
      indicator.setText("Performing commit...");
      GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT);
      handler.addParameters("-m", dialog.getCommitMessage());
      handler.endOptions();
      handler.run();

      VcsFileUtil.refreshFiles(project, modified);
    } catch (VcsException e) {
      LOG.warn(e);
      GithubNotifications.showErrorURL(
          project,
          "Can't finish GitHub sharing process",
          "Successfully created project ",
          "'" + name + "'",
          " on GitHub, but initial commit failed:<br/>" + GithubUtil.getErrorTextFromException(e),
          url);
      return false;
    }
    LOG.info("Successfully created initial commit");
    return true;
  }
  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();
  }