@NotNull
 private static GitUpdater getDefaultUpdaterForBranch(
     @NotNull Project project,
     @NotNull Git git,
     @NotNull VirtualFile root,
     @NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
     @NotNull ProgressIndicator progressIndicator,
     @NotNull UpdatedFiles updatedFiles) {
   try {
     GitLocalBranch branch = GitBranchUtil.getCurrentBranch(project, root);
     boolean rebase = false;
     if (branch != null) {
       String rebaseValue =
           GitConfigUtil.getValue(project, root, "branch." + branch.getName() + ".rebase");
       rebase = rebaseValue != null && rebaseValue.equalsIgnoreCase("true");
     }
     if (rebase) {
       return new GitRebaseUpdater(
           project, git, root, trackedBranches, progressIndicator, updatedFiles);
     }
   } catch (VcsException e) {
     LOG.info("getDefaultUpdaterForBranch branch", e);
   }
   return new GitMergeUpdater(
       project, git, root, trackedBranches, progressIndicator, updatedFiles);
 }
 @NotNull
 private Set<VcsRef> readBranches(@NotNull GitRepository repository) {
   StopWatch sw = StopWatch.start("readBranches in " + repository.getRoot().getName());
   VirtualFile root = repository.getRoot();
   repository.update();
   Collection<GitLocalBranch> localBranches = repository.getBranches().getLocalBranches();
   Collection<GitRemoteBranch> remoteBranches = repository.getBranches().getRemoteBranches();
   Set<VcsRef> refs = new THashSet<VcsRef>(localBranches.size() + remoteBranches.size());
   for (GitLocalBranch localBranch : localBranches) {
     refs.add(
         myVcsObjectsFactory.createRef(
             localBranch.getHash(), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root));
   }
   for (GitRemoteBranch remoteBranch : remoteBranches) {
     refs.add(
         myVcsObjectsFactory.createRef(
             remoteBranch.getHash(),
             remoteBranch.getNameForLocalOperations(),
             GitRefManager.REMOTE_BRANCH,
             root));
   }
   String currentRevision = repository.getCurrentRevision();
   if (currentRevision != null) { // null => fresh repository
     refs.add(
         myVcsObjectsFactory.createRef(
             HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root));
   }
   sw.report();
   return refs;
 }
  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
  private GitRemoteBranch getRemoteTrackingBranch() {
    final GitLocalBranch localBranch = this.getSourceBranch();

    return localBranch != null && this.gitRepository != null
        ? localBranch.findTrackedBranch(this.gitRepository)
        : null;
  }
  @Nullable
  public static GithubCreatePullRequestWorker createPullRequestWorker(
      @NotNull final Project project, @Nullable final VirtualFile file) {
    Git git = ServiceManager.getService(Git.class);

    GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
    if (gitRepository == null) {
      GithubNotifications.showError(
          project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
      return null;
    }
    gitRepository.update();

    Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
    if (remote == null) {
      GithubNotifications.showError(
          project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
      return null;
    }
    String remoteName = remote.getFirst().getName();
    String remoteUrl = remote.getSecond();
    GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
    if (path == null) {
      GithubNotifications.showError(
          project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
      return null;
    }

    GitLocalBranch currentBranch = gitRepository.getCurrentBranch();
    if (currentBranch == null) {
      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
      return null;
    }

    GithubAuthData auth;
    try {
      auth =
          GithubUtil.computeValueInModal(
              project,
              "Access to GitHub",
              new ThrowableConvertor<ProgressIndicator, GithubAuthData, IOException>() {
                @Override
                public GithubAuthData convert(ProgressIndicator indicator) throws IOException {
                  return GithubUtil.getValidAuthDataFromConfig(project, indicator);
                }
              });
    } catch (GithubAuthenticationCanceledException e) {
      return null;
    } catch (IOException e) {
      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
      return null;
    }

    return new GithubCreatePullRequestWorker(
        project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), auth);
  }
 /**
  * For each root check that the repository is on branch, and this branch is tracking a remote
  * branch, and the remote branch exists. If it is not true for at least one of roots, notify and
  * return false. If branch configuration is OK for all roots, return true.
  */
 private boolean checkTrackedBranchesConfigured() {
   LOG.info("checking tracked branch configuration...");
   for (GitRepository repository : myRepositories) {
     VirtualFile root = repository.getRoot();
     final GitLocalBranch branch = repository.getCurrentBranch();
     if (branch == null) {
       LOG.info("checkTrackedBranchesConfigured: current branch is null in " + repository);
       notifyImportantError(
           myProject,
           "Can't update: no current branch",
           "You are in 'detached HEAD' state, which means that you're not on any branch"
               + rootStringIfNeeded(root)
               + "Checkout a branch to make update possible.");
       return false;
     }
     GitBranchTrackInfo trackInfo = GitBranchUtil.getTrackInfoForBranch(repository, branch);
     if (trackInfo == null) {
       final String branchName = branch.getName();
       LOG.info(
           String.format(
               "checkTrackedBranchesConfigured: no track info for current branch %s in %s",
               branch, repository));
       String recommendedCommand =
           String.format(
               GitVersionSpecialty.KNOWS_SET_UPSTREAM_TO.existsIn(repository.getVcs().getVersion())
                   ? "git branch --set-upstream-to origin/%1$s %1$s"
                   : "git branch --set-upstream %1$s origin/%1$s",
               branchName);
       notifyImportantError(
           myProject,
           "Can't update: no tracked branch",
           "No tracked branch configured for branch "
               + code(branchName)
               + rootStringIfNeeded(root)
               + "To make your branch track a remote branch call, for example,<br/>"
               + "<code>"
               + recommendedCommand
               + "</code>");
       return false;
     }
     myTrackedBranches.put(root, new GitBranchPair(branch, trackInfo.getRemoteBranch()));
   }
   return true;
 }
  /* if user has changed the dropdown while we calculate the diff, this diff is out of date */
  private boolean isChangesUpToDate(final GitChangesContainer changesContainer) {

    // target branches must match
    final GitRemoteBranch targetBranch = this.getTargetBranch();
    if (changesContainer.getTargetBranchName() != null && targetBranch != null) {
      if (!changesContainer.getTargetBranchName().equals(targetBranch.getName())) {
        return false;
      }
    }

    // source branches must match
    final GitLocalBranch sourceBranch = this.getSourceBranch();
    if (changesContainer.getSourceBranchName() != null && sourceBranch != null) {
      if (!changesContainer.getSourceBranchName().equals(sourceBranch.getName())) {
        return false;
      }
    }

    return true;
  }
  private ListenableFuture<Pair<String, GitCommandResult>> doPushCommits(
      @NotNull final GitRepository gitRepository,
      @NotNull final GitLocalBranch localBranch,
      @NotNull final GitRemote gitRemote,
      @NotNull final ProgressIndicator indicator) {
    // just set the result without going off to another thread, we should already be in a background
    // task
    SettableFuture<Pair<String, GitCommandResult>> pushResult =
        SettableFuture.<Pair<String, GitCommandResult>>create();

    indicator.setText(TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_PUSH_TITLE));
    final Git git = ServiceManager.getService(Git.class);

    final GitRemoteBranch trackingBranch = localBranch.findTrackedBranch(gitRepository);

    final String createdBranchNameOnServer;
    final StringBuilder pushSpec = new StringBuilder(localBranch.getName());
    if (trackingBranch != null && trackingBranch.getRemote().equals(gitRemote)) {
      // if the tracking branch is on the same remote, we should update that
      pushSpec.append(":").append(trackingBranch.getNameForRemoteOperations());
      createdBranchNameOnServer = trackingBranch.getNameForRemoteOperations();
    } else {
      createdBranchNameOnServer = localBranch.getName();
    }

    final String fetchUrl = getFetchUrl(gitRemote);
    final String pushSpecStr = pushSpec.toString();
    final String gitRemoteName = gitRemote.getName();
    logger.debug("Pushing {} to {}: {}", pushSpecStr, gitRemoteName, fetchUrl);
    final GitCommandResult result =
        git.push(gitRepository, gitRemoteName, fetchUrl, pushSpecStr, true);

    if (result.success()) {
      pushResult.set(Pair.create(createdBranchNameOnServer, result));
    } else {
      final String errMsg = result.getErrorOutputAsJoinedString();
      pushResult.setException(new GitExecutionException(errMsg, null));
    }

    return pushResult;
  }
  @NotNull
  @Override
  public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
    if (!isRepositoryReady(root)) {
      return Collections.emptyList();
    }

    GitRepository repository = getRepository(root);
    repository.update();
    Collection<GitLocalBranch> localBranches = repository.getBranches().getLocalBranches();
    Collection<GitRemoteBranch> remoteBranches = repository.getBranches().getRemoteBranches();
    Collection<VcsRef> refs = new ArrayList<VcsRef>(localBranches.size() + remoteBranches.size());
    for (GitLocalBranch localBranch : localBranches) {
      refs.add(
          myVcsObjectsFactory.createRef(
              HashImpl.build(localBranch.getHash()),
              localBranch.getName(),
              GitRefManager.LOCAL_BRANCH,
              root));
    }
    for (GitRemoteBranch remoteBranch : remoteBranches) {
      refs.add(
          myVcsObjectsFactory.createRef(
              HashImpl.build(remoteBranch.getHash()),
              remoteBranch.getNameForLocalOperations(),
              GitRefManager.REMOTE_BRANCH,
              root));
    }
    String currentRevision = repository.getCurrentRevision();
    if (currentRevision != null) { // null => fresh repository
      refs.add(
          myVcsObjectsFactory.createRef(
              HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root));
    }

    refs.addAll(readTags(root));
    return refs;
  }