@NotNull
 private Pair<String, String> getUserNameAndEmailFromGitConfig(
     @NotNull Project project, @NotNull VirtualFile root) throws VcsException {
   String name = GitConfigUtil.getValue(project, root, GitConfigUtil.USER_NAME);
   String email = GitConfigUtil.getValue(project, root, GitConfigUtil.USER_EMAIL);
   return Pair.create(name, email);
 }
 @Nullable
 private VcsUser readCurrentUser(@NotNull Project project, @NotNull VirtualFile root)
     throws VcsException {
   String userName = GitConfigUtil.getValue(project, root, GitConfigUtil.USER_NAME);
   String userEmail =
       StringUtil.notNullize(GitConfigUtil.getValue(project, root, GitConfigUtil.USER_EMAIL));
   return userName == null ? null : myFactory.createUser(userName, userEmail);
 }
 /**
  * Setup remotes combobox. The default remote for the current branch is selected by default.
  *
  * @param project the project
  * @param root the git root
  * @param currentBranch the current branch
  * @param remoteCombobox the combobox to update
  * @param fetchUrl if true, the fetch url is shown for remotes, push otherwise
  */
 public static void setupRemotes(
     final Project project,
     final VirtualFile root,
     final String currentBranch,
     final JComboBox remoteCombobox,
     final boolean fetchUrl) {
   try {
     List<GitDeprecatedRemote> remotes = GitDeprecatedRemote.list(project, root);
     String remote = null;
     if (currentBranch != null) {
       remote = GitConfigUtil.getValue(project, root, "branch." + currentBranch + ".remote");
     }
     remoteCombobox.setRenderer(
         getGitRemoteListCellRenderer(remote, fetchUrl, remoteCombobox.getRenderer()));
     GitDeprecatedRemote toSelect = null;
     remoteCombobox.removeAllItems();
     for (GitDeprecatedRemote r : remotes) {
       remoteCombobox.addItem(r);
       if (r.name().equals(remote)) {
         toSelect = r;
       }
     }
     if (toSelect != null) {
       remoteCombobox.setSelectedItem(toSelect);
     }
   } catch (VcsException e) {
     GitVcs.getInstance(project)
         .showErrors(Collections.singletonList(e), GitBundle.getString("pull.retrieving.remotes"));
   }
 }
 @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);
 }
 private void setCoreAutoCrlfAttribute(@NotNull VirtualFile aRoot) {
   try {
     GitConfigUtil.setValue(
         myProject,
         aRoot,
         GitConfigUtil.CORE_AUTOCRLF,
         GitCrlfUtil.RECOMMENDED_VALUE,
         "--global");
   } catch (VcsException e) {
     // it is not critical: the user just will get the dialog again next time
     LOG.warn("Couldn't globally set core.autocrlf in " + aRoot, e);
   }
 }
 /**
  * Create a file that contains the specified message
  *
  * @param root a git repository root
  * @param message a message to write
  * @return a file reference
  * @throws IOException if file cannot be created
  */
 private File createMessageFile(VirtualFile root, final String message) throws IOException {
   // filter comment lines
   File file = FileUtil.createTempFile(GIT_COMMIT_MSG_FILE_PREFIX, GIT_COMMIT_MSG_FILE_EXT);
   file.deleteOnExit();
   @NonNls String encoding = GitConfigUtil.getCommitEncoding(myProject, root);
   Writer out = new OutputStreamWriter(new FileOutputStream(file), encoding);
   try {
     out.write(message);
   } finally {
     out.close();
   }
   return file;
 }
  @Nullable
  public static Pair<AbstractHash, AbstractHash> getStashTop(
      @NotNull Project project, @NotNull VirtualFile root) throws VcsException {
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH.readLockingCommand());
    GitLogParser parser = new GitLogParser(project, SHORT_HASH, SHORT_PARENTS);
    h.setSilent(true);
    h.setNoSSH(true);
    h.addParameters("list");
    h.addParameters("-n1");
    h.addParameters(parser.getPretty());

    String out;
    h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(project, root)));
    out = h.run();
    final List<GitLogRecord> gitLogRecords = parser.parse(out);
    for (GitLogRecord gitLogRecord : gitLogRecords) {
      ProgressManager.checkCanceled();

      GitSimpleHandler h1 = new GitSimpleHandler(project, root, GitCommand.LOG);
      GitLogParser parser1 = new GitLogParser(project, SHORT_HASH, SHORT_PARENTS, SUBJECT);
      h1.setSilent(true);
      h1.setNoSSH(true);
      h1.addParameters("-n1");
      h1.addParameters(parser1.getPretty());
      // h1.endOptions();
      h1.addParameters(gitLogRecord.getShortHash());

      String out1;
      out1 = h1.run();
      final List<GitLogRecord> gitLogRecords1 = parser1.parse(out1);
      assert gitLogRecords1.size() == 1;
      final GitLogRecord logRecord = gitLogRecords1.get(0);
      final String[] parentsShortHashes = logRecord.getParentsShortHashes();
      String indexCommit = null;
      // heuristics
      if (parentsShortHashes.length == 2) {
        if (logRecord.getSubject().contains(parentsShortHashes[0])) {
          indexCommit = parentsShortHashes[1];
        }
        if (logRecord.getSubject().contains(parentsShortHashes[1])) {
          indexCommit = parentsShortHashes[0];
        }
      }
      return new Pair<AbstractHash, AbstractHash>(
          AbstractHash.create(gitLogRecord.getShortHash()),
          indexCommit == null ? null : AbstractHash.create(indexCommit));
    }
    return null;
  }
  @Nullable
  public static List<Pair<String, GitCommit>> loadStashStackAsCommits(
      @NotNull Project project,
      @NotNull VirtualFile root,
      SymbolicRefsI refs,
      final String... parameters)
      throws VcsException {
    GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH.readLockingCommand());
    GitLogParser parser =
        new GitLogParser(
            project,
            GitLogParser.NameStatus.STATUS,
            SHORT_HASH,
            HASH,
            COMMIT_TIME,
            AUTHOR_NAME,
            AUTHOR_TIME,
            AUTHOR_EMAIL,
            COMMITTER_NAME,
            COMMITTER_EMAIL,
            SHORT_PARENTS,
            REF_NAMES,
            SHORT_REF_LOG_SELECTOR,
            SUBJECT,
            BODY,
            RAW_BODY);
    h.setSilent(true);
    h.setNoSSH(true);
    h.addParameters("list");
    h.addParameters(parameters);
    h.addParameters(parser.getPretty());

    String out;
    h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(project, root)));
    out = h.run();
    final List<GitLogRecord> gitLogRecords = parser.parse(out);
    final List<Pair<String, GitCommit>> result = new ArrayList<Pair<String, GitCommit>>();
    for (GitLogRecord gitLogRecord : gitLogRecords) {
      ProgressManager.checkCanceled();
      final GitCommit gitCommit = createCommit(project, refs, root, gitLogRecord);
      result.add(new Pair<String, GitCommit>(gitLogRecord.getShortenedRefLog(), gitCommit));
    }
    return result;
  }
 @Nullable
 public String getDefaultMessageFor(FilePath[] filesToCheckin) {
   LinkedHashSet<String> messages = ContainerUtil.newLinkedHashSet();
   for (VirtualFile root : GitUtil.gitRoots(Arrays.asList(filesToCheckin))) {
     VirtualFile mergeMsg = root.findFileByRelativePath(GitRepositoryFiles.GIT_MERGE_MSG);
     VirtualFile squashMsg = root.findFileByRelativePath(GitRepositoryFiles.GIT_SQUASH_MSG);
     try {
       if (mergeMsg == null && squashMsg == null) {
         continue;
       }
       String encoding = GitConfigUtil.getCommitEncoding(myProject, root);
       if (mergeMsg != null) {
         messages.add(loadMessage(mergeMsg, encoding));
       } else {
         messages.add(loadMessage(squashMsg, encoding));
       }
     } catch (IOException e) {
       if (log.isDebugEnabled()) {
         log.debug("Unable to load merge message", e);
       }
     }
   }
   return DvcsUtil.joinMessagesOrNull(messages);
 }
    private ReturnResult checkUserName() {
      Project project = myPanel.getProject();
      GitVcs vcs = GitVcs.getInstance(project);
      assert vcs != null;

      Collection<VirtualFile> notDefined = new ArrayList<VirtualFile>();
      Map<VirtualFile, Pair<String, String>> defined =
          new HashMap<VirtualFile, Pair<String, String>>();
      Collection<VirtualFile> allRoots =
          new ArrayList<VirtualFile>(
              Arrays.asList(ProjectLevelVcsManager.getInstance(project).getRootsUnderVcs(vcs)));

      Collection<VirtualFile> affectedRoots = getSelectedRoots();
      for (VirtualFile root : affectedRoots) {
        try {
          Pair<String, String> nameAndEmail = getUserNameAndEmailFromGitConfig(project, root);
          String name = nameAndEmail.getFirst();
          String email = nameAndEmail.getSecond();
          if (name == null || email == null) {
            notDefined.add(root);
          } else {
            defined.put(root, nameAndEmail);
          }
        } catch (VcsException e) {
          LOG.error("Couldn't get user.name and user.email for root " + root, e);
          // doing nothing - let commit with possibly empty user.name/email
        }
      }

      if (notDefined.isEmpty()) {
        return ReturnResult.COMMIT;
      }

      GitVersion version = vcs.getVersion();
      if (System.getenv("HOME") == null
          && GitVersionSpecialty.DOESNT_DEFINE_HOME_ENV_VAR.existsIn(version)) {
        Messages.showErrorDialog(
            project,
            "You are using Git "
                + version
                + " which doesn't define %HOME% environment variable properly.\n"
                + "Consider updating Git to a newer version "
                + "or define %HOME% to point to the place where the global .gitconfig is stored \n"
                + "(it is usually %USERPROFILE% or %HOMEDRIVE%%HOMEPATH%).",
            "HOME Variable Is Not Defined");
        return ReturnResult.CANCEL;
      }

      if (defined.isEmpty() && allRoots.size() > affectedRoots.size()) {
        allRoots.removeAll(affectedRoots);
        for (VirtualFile root : allRoots) {
          try {
            Pair<String, String> nameAndEmail = getUserNameAndEmailFromGitConfig(project, root);
            String name = nameAndEmail.getFirst();
            String email = nameAndEmail.getSecond();
            if (name != null && email != null) {
              defined.put(root, nameAndEmail);
              break;
            }
          } catch (VcsException e) {
            LOG.error("Couldn't get user.name and user.email for root " + root, e);
            // doing nothing - not critical not to find the values for other roots not affected by
            // commit
          }
        }
      }

      GitUserNameNotDefinedDialog dialog =
          new GitUserNameNotDefinedDialog(project, notDefined, affectedRoots, defined);
      dialog.show();
      if (dialog.isOK()) {
        try {
          if (dialog.isGlobal()) {
            GitConfigUtil.setValue(
                project,
                notDefined.iterator().next(),
                GitConfigUtil.USER_NAME,
                dialog.getUserName(),
                "--global");
            GitConfigUtil.setValue(
                project,
                notDefined.iterator().next(),
                GitConfigUtil.USER_EMAIL,
                dialog.getUserEmail(),
                "--global");
          } else {
            for (VirtualFile root : notDefined) {
              GitConfigUtil.setValue(project, root, GitConfigUtil.USER_NAME, dialog.getUserName());
              GitConfigUtil.setValue(
                  project, root, GitConfigUtil.USER_EMAIL, dialog.getUserEmail());
            }
          }
        } catch (VcsException e) {
          String message = "Couldn't set user.name and user.email";
          LOG.error(message, e);
          Messages.showErrorDialog(myPanel.getComponent(), message);
          return ReturnResult.CANCEL;
        }
        return ReturnResult.COMMIT;
      }
      return ReturnResult.CLOSE_WINDOW;
    }
  /**
   * Unescape path returned by Git.
   *
   * <p>If there are quotes in the file name, Git not only escapes them, but also encloses the file
   * name into quotes: <code>"\"quote"</code>
   *
   * <p>If there are spaces in the file name, Git displays the name as is, without escaping spaces
   * and without enclosing name in quotes.
   *
   * @param path a path to unescape
   * @return unescaped path ready to be searched in the VFS or file system.
   * @throws com.intellij.openapi.vcs.VcsException if the path in invalid
   */
  @NotNull
  public static String unescapePath(@NotNull String path) throws VcsException {
    final String QUOTE = "\"";
    if (path.startsWith(QUOTE) && path.endsWith(QUOTE)) {
      path = path.substring(1, path.length() - 1);
    }

    final int l = path.length();
    StringBuilder rc = new StringBuilder(l);
    for (int i = 0; i < path.length(); i++) {
      char c = path.charAt(i);
      if (c == '\\') {
        //noinspection AssignmentToForLoopParameter
        i++;
        if (i >= l) {
          throw new VcsException("Unterminated escape sequence in the path: " + path);
        }
        final char e = path.charAt(i);
        switch (e) {
          case '\\':
            rc.append('\\');
            break;
          case 't':
            rc.append('\t');
            break;
          case 'n':
            rc.append('\n');
            break;
          case '"':
            rc.append('"');
            break;
          default:
            if (VcsFileUtil.isOctal(e)) {
              // collect sequence of characters as a byte array.
              // count bytes first
              int n = 0;
              for (int j = i; j < l; ) {
                if (VcsFileUtil.isOctal(path.charAt(j))) {
                  n++;
                  for (int k = 0; k < 3 && j < l && VcsFileUtil.isOctal(path.charAt(j)); k++) {
                    //noinspection AssignmentToForLoopParameter
                    j++;
                  }
                }
                if (j + 1 >= l
                    || path.charAt(j) != '\\'
                    || !VcsFileUtil.isOctal(path.charAt(j + 1))) {
                  break;
                }
                //noinspection AssignmentToForLoopParameter
                j++;
              }
              // convert to byte array
              byte[] b = new byte[n];
              n = 0;
              while (i < l) {
                if (VcsFileUtil.isOctal(path.charAt(i))) {
                  int code = 0;
                  for (int k = 0; k < 3 && i < l && VcsFileUtil.isOctal(path.charAt(i)); k++) {
                    code = code * 8 + (path.charAt(i) - '0');
                    //noinspection AssignmentToForLoopParameter
                    i++;
                  }
                  b[n++] = (byte) code;
                }
                if (i + 1 >= l
                    || path.charAt(i) != '\\'
                    || !VcsFileUtil.isOctal(path.charAt(i + 1))) {
                  break;
                }
                //noinspection AssignmentToForLoopParameter
                i++;
              }
              //noinspection AssignmentToForLoopParameter
              i--;
              assert n == b.length;
              // add them to string
              final String encoding = GitConfigUtil.getFileNameEncoding();
              try {
                rc.append(new String(b, encoding));
              } catch (UnsupportedEncodingException e1) {
                throw new IllegalStateException(
                    "The file name encoding is unsuported: " + encoding);
              }
            } else {
              throw new VcsException(
                  "Unknown escape sequence '\\" + path.charAt(i) + "' in the path: " + path);
            }
        }
      } else {
        rc.append(c);
      }
    }
    return rc.toString();
  }