fixing compilation error
authorPavel Sher <pavel.sher@gmail.com>
Sat, 26 Nov 2011 11:52:00 +0000 (12:52 +0100)
committerPavel Sher <pavel.sher@gmail.com>
Sat, 26 Nov 2011 11:52:00 +0000 (12:52 +0100)
git-server/src/jetbrains/buildServer/buildTriggers/vcs/git/GitVcsSupport.java

index 1e88dd232477a8a03770aa189b3c93e13e530824..d42d739d2ea9e7a6f2da0346f304c084061e3740 100755 (executable)
-/*
- * Copyright 2000-2011 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jetbrains.buildServer.buildTriggers.vcs.git;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.Pair;
-import jetbrains.buildServer.ExtensionHolder;
-import jetbrains.buildServer.buildTriggers.vcs.git.submodules.SubmoduleAwareTreeIterator;
-import jetbrains.buildServer.serverSide.PropertiesProcessor;
-import jetbrains.buildServer.serverSide.impl.LogUtil;
-import jetbrains.buildServer.util.FileUtil;
-import jetbrains.buildServer.util.RecentEntriesCache;
-import jetbrains.buildServer.vcs.*;
-import jetbrains.buildServer.vcs.RepositoryState;
-import jetbrains.buildServer.vcs.impl.VcsRootImpl;
-import jetbrains.buildServer.vcs.patches.PatchBuilder;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.errors.AmbiguousObjectException;
-import org.eclipse.jgit.errors.NotSupportedException;
-import org.eclipse.jgit.errors.TransportException;
-import org.eclipse.jgit.lib.*;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevSort;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.revwalk.filter.RevFilter;
-import org.eclipse.jgit.storage.file.WindowCache;
-import org.eclipse.jgit.storage.file.WindowCacheConfig;
-import org.eclipse.jgit.transport.*;
-import org.eclipse.jgit.treewalk.AbstractTreeIterator;
-import org.eclipse.jgit.treewalk.EmptyTreeIterator;
-import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
-import org.eclipse.jgit.treewalk.filter.TreeFilter;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.*;
-import java.util.*;
-import java.util.concurrent.Callable;
-import java.util.concurrent.locks.Lock;
-import java.util.regex.Pattern;
-
-import static jetbrains.buildServer.buildTriggers.vcs.git.GitServerUtil.friendlyNotSupportedException;
-import static jetbrains.buildServer.buildTriggers.vcs.git.GitServerUtil.friendlyTransportException;
-
-
-/**
- * Git VCS support
- */
-public class GitVcsSupport extends ServerVcsSupport
-  implements VcsPersonalSupport, LabelingSupport, VcsFileContentProvider, CollectChangesBetweenRoots, BuildPatchByCheckoutRules,
-             TestConnectionSupport, BranchSupport, IncludeRuleBasedMappingProvider {
-
-  private static Logger LOG = Logger.getInstance(GitVcsSupport.class.getName());
-  private static Logger PERFORMANCE_LOG = Logger.getInstance(GitVcsSupport.class.getName() + ".Performance");
-  /**
-   * Current version cache (Pair<bare repository dir, branch name> -> current version).
-   */
-  private final RecentEntriesCache<Pair<File, String>, String> myCurrentVersionCache;
-
-  private final ExtensionHolder myExtensionHolder;
-  private volatile String myDisplayName = null;
-  private final ServerPluginConfig myConfig;
-  private final TransportFactory myTransportFactory;
-  private final FetchCommand myFetchCommand;
-  private final RepositoryManager myRepositoryManager;
-
-
-  public GitVcsSupport(@NotNull final ServerPluginConfig config,
-                       @NotNull final TransportFactory transportFactory,
-                       @NotNull final FetchCommand fetchCommand,
-                       @NotNull final RepositoryManager repositoryManager,
-                       @Nullable final ExtensionHolder extensionHolder) {
-    myConfig = config;
-    myExtensionHolder = extensionHolder;
-    myTransportFactory = transportFactory;
-    myFetchCommand = fetchCommand;
-    myRepositoryManager = repositoryManager;
-    myCurrentVersionCache = new RecentEntriesCache<Pair<File, String>, String>(myConfig.getCurrentVersionCacheSize());
-    setStreamFileThreshold();
-  }
-
-
-  private void setStreamFileThreshold() {
-    WindowCacheConfig cfg = new WindowCacheConfig();
-    cfg.setStreamFileThreshold(myConfig.getStreamFileThreshold() * WindowCacheConfig.MB);
-    WindowCache.reconfigure(cfg);
-  }
-
-
-  @NotNull
-  public List<ModificationData> collectChanges(@NotNull VcsRoot originalRoot,
-                                               @NotNull String  originalRootVersion,
-                                               @NotNull VcsRoot branchRoot,
-                                               @Nullable String  branchRootVersion,
-                                               @NotNull CheckoutRules checkoutRules) throws VcsException {
-    LOG.debug("Collecting changes [" +LogUtil.describe(originalRoot) + "-" + originalRootVersion + "].." +
-              "[" + LogUtil.describe(branchRoot) + "-" + branchRootVersion + "]");
-    if (branchRootVersion == null) {
-      LOG.warn("Branch root version is null for " + LogUtil.describe(branchRoot) + ", return empty list of changes");
-      return Collections.emptyList();
-    }
-    String forkPoint = getLastCommonVersion(originalRoot, originalRootVersion, branchRoot, branchRootVersion);
-    return collectChanges(branchRoot, forkPoint, branchRootVersion, checkoutRules);
-  }
-
-  @NotNull
-  public List<ModificationData> collectChanges(@NotNull VcsRoot root,
-                                               @NotNull String fromVersion,
-                                               @Nullable String currentVersion,
-                                               @NotNull CheckoutRules checkoutRules) throws VcsException {
-    List<ModificationData> result = new ArrayList<ModificationData>();
-    OperationContext context = createContext(root, "collecting changes");
-    try {
-      LOG.debug("Collecting changes " + fromVersion + ".." + currentVersion + " for " + context.getSettings().debugInfo());
-      if (currentVersion == null) {
-        LOG.warn("Current version is null for " + context.getSettings().debugInfo() + ", return empty list of changes");
-        return result;
-      }
-      String upperBoundSHA = GitUtils.versionRevision(currentVersion);
-      ensureRevCommitLoaded(context, context.getSettings(), upperBoundSHA);
-      String lowerBoundSHA = GitUtils.versionRevision(fromVersion);
-      Repository r = context.getRepository();
-      result.addAll(getModifications(context, r, upperBoundSHA, lowerBoundSHA, GitUtils.versionTime(fromVersion)));
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-    return result;
-  }
-  
-  
-  private List<ModificationData> getModifications(@NotNull final OperationContext context, @NotNull final Repository r, @NotNull final String upperBoundSHA, @NotNull final String lowerBoundSHA, final long timeLowerBound) throws VcsException, IOException {
-    List<ModificationData> modifications = new ArrayList<ModificationData>();
-    ModificationDataRevWalk revWalk = new ModificationDataRevWalk(context, myConfig.getFixedSubmoduleCommitSearchDepth());
-    revWalk.sort(RevSort.TOPO);
-    try {
-      revWalk.markStart(revWalk.parseCommit(ObjectId.fromString(upperBoundSHA)));
-      ObjectId lowerBoundId = ObjectId.fromString(lowerBoundSHA);
-      if (r.hasObject(lowerBoundId)) {
-        revWalk.markUninteresting(revWalk.parseCommit(lowerBoundId));
-      } else {
-        LOG.warn("From version " + lowerBoundSHA + " is not found, collecting changes based on commit time " + context.getSettings().debugInfo());
-        revWalk.limitByCommitTime(timeLowerBound);
-      }
-      while (revWalk.next() != null) {
-        modifications.add(revWalk.createModificationData());
-      }
-      return modifications;
-    } finally {
-      revWalk.release();
-    }    
-  }
-
-
-  @NotNull
-  public String getRemoteRunOnBranchPattern() {
-    return "refs/heads/remote-run/*";
-  }
-
-  @NotNull
-  public RepositoryState getCurrentState(@NotNull VcsRoot root) throws VcsException {
-    RepositoryState state = new RepositoryState();
-    for (Ref ref : getRemoteRefs(root).values()) {
-      state.addBranch(ref.getName(), ref.getObjectId().name());
-    }
-    return state;
-  }
-
-  @NotNull
-  public Map<String, String> getBranchRootOptions(@NotNull VcsRoot root, @NotNull String branchName) {
-    final Map<String, String> result = new HashMap<String, String>(root.getProperties());
-    result.put(Constants.BRANCH_NAME, branchName);
-    return result;
-  }
-
-
-  @Nullable
-  public PersonalBranchDescription getPersonalBranchDescription(@NotNull VcsRoot original, @NotNull String branchName) throws VcsException {
-    VcsRoot branchRoot = createBranchRoot(original, branchName);
-    OperationContext context = createContext(branchRoot, "find fork version");
-    PersonalBranchDescription result = null;
-    RevWalk walk = null;
-    try {
-      String originalCommit = GitUtils.versionRevision(getCurrentVersion(original));
-      String branchCommit   = GitUtils.versionRevision(getCurrentVersion(branchRoot));
-      Repository db = context.getRepository();
-      walk = new RevWalk(db);
-      walk.markStart(walk.parseCommit(ObjectId.fromString(branchCommit)));
-      walk.markUninteresting(walk.parseCommit(ObjectId.fromString(originalCommit)));
-      walk.sort(RevSort.TOPO);
-      boolean lastCommit = true;
-      String firstCommitInBranch = null;
-      String lastCommitUser = null;
-      RevCommit c;
-      while ((c = walk.next()) != null) {
-        if (lastCommit) {
-          lastCommitUser = GitServerUtil.getUser(context.getSettings(), c);
-          lastCommit = false;
-        }
-        firstCommitInBranch = c.name();
-      }
-      if (firstCommitInBranch != null && lastCommitUser != null)
-        result = new PersonalBranchDescription(firstCommitInBranch, lastCommitUser);
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      try {
-        if (walk != null)
-          walk.release();
-      } finally {
-        context.close();
-      }
-    }
-    return result;
-  }
-
-  private VcsRoot createBranchRoot(VcsRoot original, String branchName) {
-    VcsRootImpl result = new VcsRootImpl(original.getId(), original.getVcsName());
-    result.addAllProperties(original.getProperties());
-    result.addProperty(Constants.BRANCH_NAME, branchName);
-    return result;
-  }
-
-  private String getLastCommonVersion(VcsRoot baseRoot, String baseVersion, VcsRoot tipRoot, String tipVersion) throws VcsException {
-    OperationContext context = createContext(tipRoot, "find fork version");
-    Settings baseSettings = context.getSettings(baseRoot);
-    Settings tipSettings = context.getSettings();
-    LOG.debug("Find last common version between [" + baseSettings.debugInfo() + "-" + baseVersion + "].." +
-              "[" + tipSettings.debugInfo() + "-" + tipVersion + "]");
-    RevWalk walk = null;
-    try {
-      RevCommit baseCommit = ensureCommitLoaded(context, baseSettings, baseVersion);
-      RevCommit tipCommit = ensureCommitLoaded(context, tipSettings, tipVersion);
-      Repository tipRepository = context.getRepository(tipSettings);
-      walk = new RevWalk(tipRepository);
-      walk.setRevFilter(RevFilter.MERGE_BASE);
-      walk.markStart(walk.parseCommit(baseCommit.getId()));
-      walk.markStart(walk.parseCommit(tipCommit.getId()));
-      final RevCommit base = walk.next();
-      String result = GitServerUtil.makeVersion(base);
-      LOG.debug("Last common revision between " + baseSettings.debugInfo() + " and " + tipSettings.debugInfo() + " is " + result);
-      return result;
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      try {
-        if (walk != null)
-          walk.release();
-      } finally {
-        context.close();
-      }
-    }
-  }
-
-
-  public void buildPatch(@NotNull VcsRoot root,
-                         @Nullable final String fromVersion,
-                         @NotNull String toVersion,
-                         @NotNull final PatchBuilder builder,
-                         @NotNull CheckoutRules checkoutRules) throws IOException, VcsException {
-    final OperationContext context = createContext(root, "patch building");
-    final boolean debugFlag = LOG.isDebugEnabled();
-    final boolean debugInfoOnEachCommit = myConfig.isPrintDebugInfoOnEachCommit();
-    try {
-      final Repository r = context.getRepository();
-      VcsChangeTreeWalk tw = null;
-      try {
-        RevCommit toCommit = ensureRevCommitLoaded(context, context.getSettings(), GitUtils.versionRevision(toVersion));
-        if (toCommit == null) {
-          throw new VcsException("Missing commit for version: " + toVersion);
-        }
-        tw = new VcsChangeTreeWalk(r, context.getSettings().debugInfo());
-        tw.setFilter(TreeFilter.ANY_DIFF);
-        tw.setRecursive(true);
-        context.addTree(tw, r, toCommit, false);
-        if (fromVersion != null) {
-          if (debugFlag) {
-            LOG.debug("Creating patch " + fromVersion + ".." + toVersion + " for " + context.getSettings().debugInfo());
-          }
-          RevCommit fromCommit = getCommit(r, GitUtils.versionRevision(fromVersion));
-          if (fromCommit == null) {
-            throw new IncrementalPatchImpossibleException("The form commit " + fromVersion + " is not available in the repository");
-          }
-          context.addTree(tw, r, fromCommit, true);
-        } else {
-          if (debugFlag) {
-            LOG.debug("Creating clean patch " + toVersion + " for " + context.getSettings().debugInfo());
-          }
-          tw.addTree(new EmptyTreeIterator());
-        }
-        final List<Callable<Void>> actions = new LinkedList<Callable<Void>>();
-        while (tw.next()) {
-          final String path = tw.getPathString();
-          final String mapped = checkoutRules.map(path);
-          if (mapped == null) {
-            continue;
-          }
-          if (debugFlag && debugInfoOnEachCommit) {
-            LOG.debug("File found " + tw.treeWalkInfo(path) + " for " + context.getSettings().debugInfo());
-          }
-          switch (tw.classifyChange()) {
-            case UNCHANGED:
-              // change is ignored
-              continue;
-            case MODIFIED:
-            case ADDED:
-            case FILE_MODE_CHANGED:
-              if (!FileMode.GITLINK.equals(tw.getFileMode(0))) {
-                final String mode = tw.getModeDiff();
-                if (mode != null && LOG.isDebugEnabled())
-                  LOG.debug("The mode change " + mode + " is detected for " + tw.treeWalkInfo(path));
-                final ObjectId id = tw.getObjectId(0);
-                final Repository objRep = getRepository(r, tw, 0);
-                final Callable<Void> action = new Callable<Void>() {
-                  public Void call() throws Exception {
-                    InputStream objectStream = null;
-                    try {
-                      final ObjectLoader loader = objRep.open(id);
-                      if (loader == null) {
-                        throw new IOException("Unable to find blob " + id + (path == null ? "" : "(" + path + ")") + " in repository " + r);
-                      }
-                      objectStream = loader.isLarge() ? loader.openStream() : new ByteArrayInputStream(loader.getCachedBytes());
-                      builder.changeOrCreateBinaryFile(GitUtils.toFile(mapped), mode, objectStream, loader.getSize());
-                    } catch (Error e) {
-                      LOG.error("Unable to load file: " + path + "(" + id.name() + ") from: " + context.getSettings().debugInfo());
-                      throw e;
-                    } catch (Exception e) {
-                      LOG.error("Unable to load file: " + path + "(" + id.name() + ") from: " + context.getSettings().debugInfo());
-                      throw e;
-                    } finally {
-                      if (objectStream != null) objectStream.close();
-                    }
-                    return null;
-                  }
-                };
-                if (fromVersion == null) {
-                  // clean patch, we aren't going to see any deletes
-                  action.call();
-                } else {
-                  actions.add(action);
-                }
-              }
-              break;
-            case DELETED:
-              if (!FileMode.GITLINK.equals(tw.getFileMode(0))) {
-                builder.deleteFile(GitUtils.toFile(mapped), true);
-              }
-              break;
-            default:
-              throw new IllegalStateException("Unknown change type");
-          }
-        }
-        for (Callable<Void> a : actions) {
-          a.call();
-        }
-      } finally {
-        if (tw != null) tw.release();
-      }
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-
-  @NotNull
-  public byte[] getContent(@NotNull VcsModification vcsModification,
-                           @NotNull VcsChangeInfo change,
-                           @NotNull VcsChangeInfo.ContentType contentType,
-                           @NotNull VcsRoot vcsRoot)
-    throws VcsException {
-    String version = contentType == VcsChangeInfo.ContentType.BEFORE_CHANGE
-                     ? change.getBeforeChangeRevisionNumber()
-                     : change.getAfterChangeRevisionNumber();
-    String file = change.getRelativeFileName();
-    return getContent(file, vcsRoot, version);
-  }
-
-  @NotNull
-  public byte[] getContent(@NotNull String filePath, @NotNull VcsRoot root, @NotNull String version) throws VcsException {
-    OperationContext context = createContext(root, "retrieving content");
-    try {
-      final long start = System.currentTimeMillis();
-      Repository r = context.getRepository();
-      final TreeWalk tw = new TreeWalk(r);
-      try {
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Getting data from " + version + ":" + filePath + " for " + context.getSettings().debugInfo());
-        }
-        final String rev = GitUtils.versionRevision(version);
-        RevCommit c = ensureRevCommitLoaded(context, context.getSettings(), rev);
-        tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(filePath)));
-        tw.setRecursive(tw.getFilter().shouldBeRecursive());
-        context.addTree(tw, r, c, true);
-        if (!tw.next()) {
-          throw new VcsFileNotFoundException("The file " + filePath + " could not be found in " + rev + context.getSettings().debugInfo());
-        }
-        final byte[] data = loadObject(r, tw, 0);
-        if (LOG.isDebugEnabled()) {
-          LOG.debug(
-            "File retrieved " + version + ":" + filePath + " (hash = " + tw.getObjectId(0) + ", length = " + data.length + ") for " +
-            context.getSettings().debugInfo());
-        }
-        return data;
-      } finally {
-        final long finish = System.currentTimeMillis();
-        if (PERFORMANCE_LOG.isDebugEnabled()) {
-          PERFORMANCE_LOG.debug("[getContent] root=" + context.getSettings().debugInfo() + ", file=" + filePath + ", get object content: " + (finish - start) + "ms");
-        }
-        tw.release();
-      }
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-  /**
-   * Load bytes that correspond to the position in the tree walker
-   *
-   * @param r   the initial repository
-   * @param tw  the tree walker
-   * @param nth the tree in the tree wailer
-   * @return loaded bytes
-   * @throws IOException if there is an IO error
-   */
-  private byte[] loadObject(Repository r, TreeWalk tw, final int nth) throws IOException {
-    ObjectId id = tw.getObjectId(nth);
-    Repository objRep = getRepository(r, tw, nth);
-    final String path = tw.getPathString();
-    return loadObject(objRep, path, id);
-  }
-
-  /**
-   * Load object by blob ID
-   *
-   * @param r    the repository
-   * @param path the path (might be null)
-   * @param id   the object id
-   * @return the object's bytes
-   * @throws IOException in case of IO problem
-   */
-  private byte[] loadObject(Repository r, String path, ObjectId id) throws IOException {
-    final ObjectLoader loader = r.open(id);
-    if (loader == null) {
-      throw new IOException("Unable to find blob " + id + (path == null ? "" : "(" + path + ")") + " in repository " + r);
-    }
-    if (loader.isLarge()) {
-      assert loader.getSize() < Integer.MAX_VALUE;
-      ByteArrayOutputStream output = new ByteArrayOutputStream((int) loader.getSize());
-      loader.copyTo(output);
-      return output.toByteArray();
-    } else {
-      return loader.getCachedBytes();
-    }
-  }
-
-  private RevCommit ensureCommitLoaded(OperationContext context, Settings rootSettings, String commitWithDate) throws Exception {
-    final String commit = GitUtils.versionRevision(commitWithDate);
-    return ensureRevCommitLoaded(context, rootSettings, commit);
-  }
-
-  private RevCommit ensureRevCommitLoaded(OperationContext context, Settings settings, String commitSHA) throws Exception {
-    Repository db = context.getRepository(settings);
-    RevCommit result = null;
-    try {
-      final long start = System.currentTimeMillis();
-      result = getCommit(db, commitSHA);
-      final long finish = System.currentTimeMillis();
-      if (PERFORMANCE_LOG.isDebugEnabled()) {
-        PERFORMANCE_LOG.debug("[ensureCommitLoaded] root=" + settings.debugInfo() + ", commit=" + commitSHA + ", local commit lookup: " + (finish - start) + "ms");
-      }
-    } catch (IOException ex) {
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("IO problem for commit " + commitSHA + " in " + settings.debugInfo(), ex);
-      }
-    }
-    if (result == null) {
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("Commit " + commitSHA + " is not in the repository for " + settings.debugInfo() + ", fetching data... ");
-      }
-      fetchBranchData(settings, db);
-      result = getCommit(db, commitSHA);
-      if (result == null) {
-        throw new VcsException("The version name could not be resolved " + commitSHA + "(" + settings.getRepositoryFetchURL().toString() + "#" + settings.getRef() + ")");
-      }
-    }
-    return result;
-  }
-
-  RevCommit getCommit(Repository repository, String commitSHA) throws IOException {
-    return getCommit(repository, ObjectId.fromString(commitSHA));
-  }
-
-  public RevCommit getCommit(Repository repository, ObjectId commitId) throws IOException {
-    final long start = System.currentTimeMillis();
-    RevWalk walk = new RevWalk(repository);
-    try {
-      return walk.parseCommit(commitId);
-    } finally {
-      walk.release();
-      final long finish = System.currentTimeMillis();
-      if (PERFORMANCE_LOG.isDebugEnabled()) {
-        PERFORMANCE_LOG.debug("[RevWalk.parseCommit] repository=" + repository.getDirectory().getAbsolutePath() + ", commit=" + commitId.name() + ", took: " + (finish - start) + "ms");
-      }
-    }
-  }
-
-  @NotNull
-  public String getName() {
-    return Constants.VCS_NAME;
-  }
-
-  @NotNull
-  public String getDisplayName() {
-    initDisplayNameIfRequired();
-    return myDisplayName;
-  }
-
-  private void initDisplayNameIfRequired() {
-    if (myDisplayName == null) {
-      if (myExtensionHolder != null) {
-        boolean communityPluginFound = false;
-        final Collection<VcsSupportContext> vcsPlugins = myExtensionHolder.getServices(VcsSupportContext.class);
-        for (VcsSupportContext plugin : vcsPlugins) {
-          if (plugin.getCore().getName().equals("git")) {
-            communityPluginFound = true;
-          }
-        }
-        if (communityPluginFound) {
-          myDisplayName = "Git (Jetbrains plugin)";
-        } else {
-          myDisplayName = "Git";
-        }
-      } else {
-        myDisplayName = "Git (Jetbrains plugin)";
-      }
-    }
-  }
-
-  public PropertiesProcessor getVcsPropertiesProcessor() {
-    return new VcsPropertiesProcessor();
-  }
-
-  @NotNull
-  public String getVcsSettingsJspFilePath() {
-    return "gitSettings.jsp";
-  }
-
-  @NotNull
-  public String describeVcsRoot(VcsRoot root) {
-    final String branch = root.getProperty(Constants.BRANCH_NAME);
-    return root.getProperty(Constants.FETCH_URL) + "#" + (branch == null ? "master" : branch);
-  }
-
-  public Map<String, String> getDefaultVcsProperties() {
-    final HashMap<String, String> map = new HashMap<String, String>();
-    map.put(Constants.BRANCH_NAME, "master");
-    map.put(Constants.IGNORE_KNOWN_HOSTS, "true");
-    return map;
-  }
-
-  public String getVersionDisplayName(@NotNull String version, @NotNull VcsRoot root) throws VcsException {
-    return GitServerUtil.displayVersion(version);
-  }
-
-  @NotNull
-  public Comparator<String> getVersionComparator() {
-    return GitUtils.VERSION_COMPARATOR;
-  }
-
-  @NotNull
-  public String getCurrentVersion(@NotNull VcsRoot root) throws VcsException {
-    OperationContext context = createContext(root, "retrieving current version");
-    Settings s = context.getSettings();
-    try {
-      Repository r = context.getRepository();
-      String refName = GitUtils.expandRef(s.getRef());
-
-      if (!myConfig.isSeparateProcessForFetch() || isRemoteRefUpdated(root, r, s, refName))
-        fetchBranchData(s, r);
-
-      Ref branchRef = r.getRef(refName);
-      if (branchRef == null) {
-        throw new VcsException("The ref '" + refName + "' could not be resolved");
-      }
-      String cachedCurrentVersion = getCachedCurrentVersion(s.getRepositoryDir(), s.getRef());
-      if (cachedCurrentVersion != null && GitUtils.versionRevision(cachedCurrentVersion).equals(branchRef.getObjectId().name())) {
-        return cachedCurrentVersion;
-      } else {
-        RevCommit c = getCommit(r, branchRef.getObjectId());
-        if (c == null) {
-          throw new VcsException("The ref '" + refName + "' could not be resolved");
-        }
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Current version: " + c.getId().name() + " " + s.debugInfo());
-        }
-        final String currentVersion = GitServerUtil.makeVersion(c);
-        setCachedCurrentVersion(s.getRepositoryDir(), s.getRef(), currentVersion);
-        GitMapFullPath.invalidateRevisionsCache(root);
-        return currentVersion;
-      }
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-
-  private boolean isRemoteRefUpdated(@NotNull VcsRoot root, @NotNull Repository db, @NotNull Settings s, @NotNull String refName) throws Exception {
-    Map<String, Ref> remoteRefs = getRemoteRefs(root, db, s);
-    Ref remoteRef = remoteRefs.get(refName);
-    if (remoteRef == null)
-      return true;
-
-    String cachedCurrentVersion = getCachedCurrentVersion(s.getRepositoryDir(), s.getRef());
-    return cachedCurrentVersion == null || !remoteRef.getObjectId().name().equals(GitUtils.versionRevision(cachedCurrentVersion));
-  }
-
-
-  /**
-   * Return cached current version for branch in repository in specified dir, or null if no cache version found.
-   */
-  private String getCachedCurrentVersion(File repositoryDir, String branchName) {
-    return myCurrentVersionCache.get(Pair.create(repositoryDir, branchName));
-  }
-
-  /**
-   * Save current version for branch of repository in cache.
-   */
-  private void setCachedCurrentVersion(File repositoryDir, String branchName, String currentVersion) {
-    myCurrentVersionCache.put(Pair.create(repositoryDir, branchName), currentVersion);
-  }
-
-  public boolean sourcesUpdatePossibleIfChangesNotFound(@NotNull VcsRoot root) {
-    return true;
-  }
-
-  /**
-   * Fetch data for the branch
-   *
-   * @param settings   settings for the root
-   * @param repository the repository
-   * @throws Exception if there is a problem with fetching data
-   */
-  private void fetchBranchData(Settings settings, Repository repository) throws Exception {
-    final String refName = GitUtils.expandRef(settings.getRef());
-    RefSpec spec = new RefSpec().setSource(refName).setDestination(refName).setForceUpdate(true);
-    fetch(repository, settings.getRepositoryFetchURL(), spec, settings.getAuthSettings());
-  }
-
-
-  public void fetch(Repository db, URIish fetchURI, Collection<RefSpec> refspecs, Settings.AuthSettings auth) throws NotSupportedException, VcsException, TransportException {
-    File repositoryDir = db.getDirectory();
-    assert repositoryDir != null : "Non-local repository";
-    Lock rmLock = myRepositoryManager.getRmLock(repositoryDir).readLock();
-    rmLock.lock();
-    try {
-      final long start = System.currentTimeMillis();
-      synchronized (myRepositoryManager.getWriteLock(repositoryDir)) {
-        final long finish = System.currentTimeMillis();
-        PERFORMANCE_LOG.debug("[waitForWriteLock] repository: " + repositoryDir.getAbsolutePath() + ", took " + (finish - start) + "ms");
-        myFetchCommand.fetch(db, fetchURI, refspecs, auth);
-      }
-    } finally {
-      rmLock.unlock();
-    }
-  }
-  /**
-   * Make fetch into local repository (it.s getDirectory() should be != null)
-   *
-   * @param db repository
-   * @param fetchURI uri to fetch
-   * @param refspec refspec
-   * @param auth auth settings
-   */
-  public void fetch(Repository db, URIish fetchURI, RefSpec refspec, Settings.AuthSettings auth) throws NotSupportedException, VcsException, TransportException {
-    fetch(db, fetchURI, Collections.singletonList(refspec), auth);
-  }
-
-
-  public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException {
-    OperationContext context = createContext(vcsRoot, "connection test");
-    TestConnectionCommand command = new TestConnectionCommand(myTransportFactory, myRepositoryManager);
-    try {
-      return command.testConnection(context);
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-
-  @Override
-  public TestConnectionSupport getTestConnectionSupport() {
-    return this;
-  }
-
-  public OperationContext createContext(VcsRoot root, String operation) {
-    return new OperationContext(this, myRepositoryManager, root, operation);
-  }
-
-  public LabelingSupport getLabelingSupport() {
-    return this;
-  }
-
-  @NotNull
-  public VcsFileContentProvider getContentProvider() {
-    return this;
-  }
-
-  @NotNull
-  public CollectChangesPolicy getCollectChangesPolicy() {
-    return this;
-  }
-
-  @NotNull
-  public BuildPatchPolicy getBuildPatchPolicy() {
-    return this;
-  }
-
-  public String label(@NotNull String label, @NotNull String version, @NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules)
-    throws VcsException {
-    OperationContext context = createContext(root, "labelling");
-    Settings s = context.getSettings();
-    try {
-      Repository r = context.getRepository();
-      String commitSHA = GitUtils.versionRevision(version);
-      RevCommit commit = ensureRevCommitLoaded(context, s, commitSHA);
-      Git git = new Git(r);
-      git.tag().setName(label).setObjectId(commit).call();
-      String tagRef = GitUtils.tagName(label);
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("Tag created  " + label + "=" + version + " for " + s.debugInfo());
-      }
-      synchronized (myRepositoryManager.getWriteLock(s.getRepositoryDir())) {
-        final Transport tn = myTransportFactory.createTransport(r, s.getRepositoryPushURL(), s.getAuthSettings());
-        try {
-          final PushConnection c = tn.openPush();
-          try {
-            RemoteRefUpdate ru = new RemoteRefUpdate(r, tagRef, tagRef, false, null, null);
-            c.push(NullProgressMonitor.INSTANCE, Collections.singletonMap(tagRef, ru));
-            LOG.info("Tag  " + label + "=" + version + " pushed with status " + ru.getStatus() + " for " + s.debugInfo());
-            switch (ru.getStatus()) {
-              case UP_TO_DATE:
-              case OK:
-                break;
-              default:
-                throw new VcsException("The remote tag was not created (" + ru.getStatus() + "): " + label);
-            }
-          } finally {
-            c.close();
-          }
-          return label;
-        } finally {
-          tn.close();
-        }
-      }
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-  /**
-   * Get repository from tree walker
-   *
-   * @param r   the initial repository
-   * @param tw  the tree walker
-   * @param nth the position
-   * @return the actual repository
-   */
-  private Repository getRepository(Repository r, TreeWalk tw, int nth) {
-    Repository objRep;
-    AbstractTreeIterator ti = tw.getTree(nth, AbstractTreeIterator.class);
-    if (ti instanceof SubmoduleAwareTreeIterator) {
-      objRep = ((SubmoduleAwareTreeIterator)ti).getRepository();
-    } else {
-      objRep = r;
-    }
-    return objRep;
-  }
-
-  @Override
-  public VcsPersonalSupport getPersonalSupport() {
-    return this;
-  }
-
-  /**
-   * Expected fullPath format:
-   * <p/>
-   * "<git revision hash>|<repository url>|<file relative path>"
-   *
-   * @param rootEntry indicates the association between VCS root and build configuration
-   * @param fullPath  change path from IDE patch
-   * @return the mapped path
-   */
-  @NotNull
-  public Collection<String> mapFullPath(@NotNull final VcsRootEntry rootEntry, @NotNull final String fullPath) {
-    OperationContext context = createContext(rootEntry.getVcsRoot(), "map full path");
-    try {
-      return new GitMapFullPath(context, this, rootEntry, fullPath).mapFullPath();
-    } catch (VcsException e) {
-      LOG.error(e);
-      return Collections.emptySet();
-    } finally {
-      context.close();
-    }
-  }
-
-  @Override
-  public boolean isAgentSideCheckoutAvailable() {
-    return true;
-  }
-
-
-  @Override
-  public UrlSupport getUrlSupport() {
-    return new GitUrlSupport();
-  }
-
-
-  public List<String> getRemoteBranches(@NotNull final VcsRoot root, @NotNull final String pattern) throws VcsException {
-    Collection<Ref> remotes = getRemoteRefs(root).values();
-    Pattern p = Pattern.compile(pattern);
-    List<String> result = new ArrayList<String>();
-    for (Ref ref : remotes) {
-      if (p.matcher(ref.getName()).matches()) {
-        result.add(ref.getName());
-      }
-    }
-    return result;
-  }
-
-  @NotNull
-  private Map<String, Ref> getRemoteRefs(@NotNull final VcsRoot root) throws VcsException {
-    OperationContext context = createContext(root, "list remote refs");
-    Settings s = context.getSettings();
-    File tmpDir = null;
-    try {
-      tmpDir = FileUtil.createTempDirectory("git-ls-remote", "");
-      s.setUserDefinedRepositoryPath(tmpDir);
-      Repository db = context.getRepository();
-      return getRemoteRefs(root, db, s);
-    } catch (Exception e) {
-      throw context.wrapException(e);
-    } finally {
-      context.close();
-      if (tmpDir != null) {
-        myRepositoryManager.cleanLocksFor(tmpDir);
-        FileUtil.delete(tmpDir);
-      }
-    }
-  }
-
-
-  @NotNull
-  private Map<String, Ref> getRemoteRefs(@NotNull final VcsRoot root, @NotNull Repository db, @NotNull Settings s) throws Exception {
-    Transport transport = null;
-    FetchConnection connection = null;
-    try {
-      transport = myTransportFactory.createTransport(db, s.getRepositoryFetchURL(), s.getAuthSettings());
-      connection = transport.openFetch();
-      return connection.getRefsMap();
-    } catch (NotSupportedException nse) {
-      throw friendlyNotSupportedException(root, s, nse);
-    } catch (TransportException te) {
-      throw friendlyTransportException(te);
-    } finally {
-      if (connection != null) connection.close();
-      if (transport != null) transport.close();
-    }
-  }
-
-  @NotNull
-  private ObjectId getVcsRootGitId(final @NotNull VcsRoot root) throws VcsException{
-    final OperationContext context = createContext(root, "client-mapping");
-    try {
-      final Settings gitSettings = context.getSettings(root);
-      final Repository gitRepo = context.getRepository(gitSettings);
-      if(gitRepo == null){
-        throw new VcsException(String.format("Could not find Git Repository for '%s'", root.getName()));
-      }
-      final ObjectId objectId = gitRepo.resolve(gitSettings.getRef());
-      if(objectId == null){
-        throw new VcsException(String.format("Could not resolve Git Reference '%s'", gitSettings.getRef()));
-      }
-      return objectId;
-    } catch (AmbiguousObjectException e) {
-      throw new VcsException(e);
-    } catch (IOException e) {
-      throw new VcsException(e);
-    } finally {
-      context.close();
-    }
-  }
-
-  public Collection<VcsClientMapping> getClientMapping(final @NotNull VcsRoot root, final @NotNull IncludeRule rule) throws VcsException {
-    final ObjectId gitObjId = getVcsRootGitId(root);
-    return Collections.singletonList(new VcsClientMapping(String.format("%s||%s", gitObjId.name(), rule.getFrom()), rule.getTo()));
-  }
-
-  @Override
-  public boolean isDAGBasedVcs() {
-    return true;
-  }
-}
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.buildTriggers.vcs.git;\r
+\r
+import com.intellij.openapi.diagnostic.Logger;\r
+import com.intellij.openapi.util.Pair;\r
+import jetbrains.buildServer.ExtensionHolder;\r
+import jetbrains.buildServer.buildTriggers.vcs.git.submodules.SubmoduleAwareTreeIterator;\r
+import jetbrains.buildServer.serverSide.PropertiesProcessor;\r
+import jetbrains.buildServer.serverSide.impl.LogUtil;\r
+import jetbrains.buildServer.util.FileUtil;\r
+import jetbrains.buildServer.util.RecentEntriesCache;\r
+import jetbrains.buildServer.vcs.*;\r
+import jetbrains.buildServer.vcs.RepositoryState;\r
+import jetbrains.buildServer.vcs.impl.VcsRootImpl;\r
+import jetbrains.buildServer.vcs.patches.PatchBuilder;\r
+import org.eclipse.jgit.api.Git;\r
+import org.eclipse.jgit.errors.AmbiguousObjectException;\r
+import org.eclipse.jgit.errors.NotSupportedException;\r
+import org.eclipse.jgit.errors.TransportException;\r
+import org.eclipse.jgit.lib.*;\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+import org.eclipse.jgit.revwalk.RevSort;\r
+import org.eclipse.jgit.revwalk.RevWalk;\r
+import org.eclipse.jgit.revwalk.filter.RevFilter;\r
+import org.eclipse.jgit.storage.file.WindowCache;\r
+import org.eclipse.jgit.storage.file.WindowCacheConfig;\r
+import org.eclipse.jgit.transport.*;\r
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;\r
+import org.eclipse.jgit.treewalk.EmptyTreeIterator;\r
+import org.eclipse.jgit.treewalk.TreeWalk;\r
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;\r
+import org.eclipse.jgit.treewalk.filter.TreeFilter;\r
+import org.jetbrains.annotations.NotNull;\r
+import org.jetbrains.annotations.Nullable;\r
+\r
+import java.io.*;\r
+import java.util.*;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.locks.Lock;\r
+import java.util.regex.Pattern;\r
+\r
+import static jetbrains.buildServer.buildTriggers.vcs.git.GitServerUtil.friendlyNotSupportedException;\r
+import static jetbrains.buildServer.buildTriggers.vcs.git.GitServerUtil.friendlyTransportException;\r
+\r
+\r
+/**\r
+ * Git VCS support\r
+ */\r
+public class GitVcsSupport extends ServerVcsSupport\r
+  implements VcsPersonalSupport, LabelingSupport, VcsFileContentProvider, CollectChangesBetweenRoots, BuildPatchByCheckoutRules,\r
+             TestConnectionSupport, BranchSupport, IncludeRuleBasedMappingProvider {\r
+\r
+  private static Logger LOG = Logger.getInstance(GitVcsSupport.class.getName());\r
+  private static Logger PERFORMANCE_LOG = Logger.getInstance(GitVcsSupport.class.getName() + ".Performance");\r
+  /**\r
+   * Current version cache (Pair<bare repository dir, branch name> -> current version).\r
+   */\r
+  private final RecentEntriesCache<Pair<File, String>, String> myCurrentVersionCache;\r
+\r
+  private final ExtensionHolder myExtensionHolder;\r
+  private volatile String myDisplayName = null;\r
+  private final ServerPluginConfig myConfig;\r
+  private final TransportFactory myTransportFactory;\r
+  private final FetchCommand myFetchCommand;\r
+  private final RepositoryManager myRepositoryManager;\r
+\r
+\r
+  public GitVcsSupport(@NotNull final ServerPluginConfig config,\r
+                       @NotNull final TransportFactory transportFactory,\r
+                       @NotNull final FetchCommand fetchCommand,\r
+                       @NotNull final RepositoryManager repositoryManager,\r
+                       @Nullable final ExtensionHolder extensionHolder) {\r
+    myConfig = config;\r
+    myExtensionHolder = extensionHolder;\r
+    myTransportFactory = transportFactory;\r
+    myFetchCommand = fetchCommand;\r
+    myRepositoryManager = repositoryManager;\r
+    myCurrentVersionCache = new RecentEntriesCache<Pair<File, String>, String>(myConfig.getCurrentVersionCacheSize());\r
+    setStreamFileThreshold();\r
+  }\r
+\r
+\r
+  private void setStreamFileThreshold() {\r
+    WindowCacheConfig cfg = new WindowCacheConfig();\r
+    cfg.setStreamFileThreshold(myConfig.getStreamFileThreshold() * WindowCacheConfig.MB);\r
+    WindowCache.reconfigure(cfg);\r
+  }\r
+\r
+\r
+  @NotNull\r
+  public List<ModificationData> collectChanges(@NotNull VcsRoot originalRoot,\r
+                                               @NotNull String  originalRootVersion,\r
+                                               @NotNull VcsRoot branchRoot,\r
+                                               @Nullable String  branchRootVersion,\r
+                                               @NotNull CheckoutRules checkoutRules) throws VcsException {\r
+    LOG.debug("Collecting changes [" +LogUtil.describe(originalRoot) + "-" + originalRootVersion + "].." +\r
+              "[" + LogUtil.describe(branchRoot) + "-" + branchRootVersion + "]");\r
+    if (branchRootVersion == null) {\r
+      LOG.warn("Branch root version is null for " + LogUtil.describe(branchRoot) + ", return empty list of changes");\r
+      return Collections.emptyList();\r
+    }\r
+    String forkPoint = getLastCommonVersion(originalRoot, originalRootVersion, branchRoot, branchRootVersion);\r
+    return collectChanges(branchRoot, forkPoint, branchRootVersion, checkoutRules);\r
+  }\r
+\r
+  @NotNull\r
+  public List<ModificationData> collectChanges(@NotNull VcsRoot root,\r
+                                               @NotNull String fromVersion,\r
+                                               @Nullable String currentVersion,\r
+                                               @NotNull CheckoutRules checkoutRules) throws VcsException {\r
+    List<ModificationData> result = new ArrayList<ModificationData>();\r
+    OperationContext context = createContext(root, "collecting changes");\r
+    try {\r
+      LOG.debug("Collecting changes " + fromVersion + ".." + currentVersion + " for " + context.getSettings().debugInfo());\r
+      if (currentVersion == null) {\r
+        LOG.warn("Current version is null for " + context.getSettings().debugInfo() + ", return empty list of changes");\r
+        return result;\r
+      }\r
+      String upperBoundSHA = GitUtils.versionRevision(currentVersion);\r
+      ensureRevCommitLoaded(context, context.getSettings(), upperBoundSHA);\r
+      String lowerBoundSHA = GitUtils.versionRevision(fromVersion);\r
+      Repository r = context.getRepository();\r
+      result.addAll(getModifications(context, r, upperBoundSHA, lowerBoundSHA, GitUtils.versionTime(fromVersion)));\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+    return result;\r
+  }\r
+  \r
+  \r
+  private List<ModificationData> getModifications(@NotNull final OperationContext context, @NotNull final Repository r, @NotNull final String upperBoundSHA, @NotNull final String lowerBoundSHA, final long timeLowerBound) throws VcsException, IOException {\r
+    List<ModificationData> modifications = new ArrayList<ModificationData>();\r
+    ModificationDataRevWalk revWalk = new ModificationDataRevWalk(context, myConfig.getFixedSubmoduleCommitSearchDepth());\r
+    revWalk.sort(RevSort.TOPO);\r
+    try {\r
+      revWalk.markStart(revWalk.parseCommit(ObjectId.fromString(upperBoundSHA)));\r
+      ObjectId lowerBoundId = ObjectId.fromString(lowerBoundSHA);\r
+      if (r.hasObject(lowerBoundId)) {\r
+        revWalk.markUninteresting(revWalk.parseCommit(lowerBoundId));\r
+      } else {\r
+        LOG.warn("From version " + lowerBoundSHA + " is not found, collecting changes based on commit time " + context.getSettings().debugInfo());\r
+        revWalk.limitByCommitTime(timeLowerBound);\r
+      }\r
+      while (revWalk.next() != null) {\r
+        modifications.add(revWalk.createModificationData());\r
+      }\r
+      return modifications;\r
+    } finally {\r
+      revWalk.release();\r
+    }    \r
+  }\r
+\r
+\r
+  @NotNull\r
+  public String getRemoteRunOnBranchPattern() {\r
+    return "refs/heads/remote-run/*";\r
+  }\r
+\r
+  @NotNull\r
+  public RepositoryState getCurrentState(@NotNull VcsRoot root) throws VcsException {\r
+    RepositoryState state = new RepositoryStateImpl();\r
+    for (Ref ref : getRemoteRefs(root).values()) {\r
+      state.addBranch(ref.getName(), ref.getObjectId().name());\r
+    }\r
+    return state;\r
+  }\r
+\r
+  @NotNull\r
+  public Map<String, String> getBranchRootOptions(@NotNull VcsRoot root, @NotNull String branchName) {\r
+    final Map<String, String> result = new HashMap<String, String>(root.getProperties());\r
+    result.put(Constants.BRANCH_NAME, branchName);\r
+    return result;\r
+  }\r
+\r
+\r
+  @Nullable\r
+  public PersonalBranchDescription getPersonalBranchDescription(@NotNull VcsRoot original, @NotNull String branchName) throws VcsException {\r
+    VcsRoot branchRoot = createBranchRoot(original, branchName);\r
+    OperationContext context = createContext(branchRoot, "find fork version");\r
+    PersonalBranchDescription result = null;\r
+    RevWalk walk = null;\r
+    try {\r
+      String originalCommit = GitUtils.versionRevision(getCurrentVersion(original));\r
+      String branchCommit   = GitUtils.versionRevision(getCurrentVersion(branchRoot));\r
+      Repository db = context.getRepository();\r
+      walk = new RevWalk(db);\r
+      walk.markStart(walk.parseCommit(ObjectId.fromString(branchCommit)));\r
+      walk.markUninteresting(walk.parseCommit(ObjectId.fromString(originalCommit)));\r
+      walk.sort(RevSort.TOPO);\r
+      boolean lastCommit = true;\r
+      String firstCommitInBranch = null;\r
+      String lastCommitUser = null;\r
+      RevCommit c;\r
+      while ((c = walk.next()) != null) {\r
+        if (lastCommit) {\r
+          lastCommitUser = GitServerUtil.getUser(context.getSettings(), c);\r
+          lastCommit = false;\r
+        }\r
+        firstCommitInBranch = c.name();\r
+      }\r
+      if (firstCommitInBranch != null && lastCommitUser != null)\r
+        result = new PersonalBranchDescription(firstCommitInBranch, lastCommitUser);\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      try {\r
+        if (walk != null)\r
+          walk.release();\r
+      } finally {\r
+        context.close();\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  private VcsRoot createBranchRoot(VcsRoot original, String branchName) {\r
+    VcsRootImpl result = new VcsRootImpl(original.getId(), original.getVcsName());\r
+    result.addAllProperties(original.getProperties());\r
+    result.addProperty(Constants.BRANCH_NAME, branchName);\r
+    return result;\r
+  }\r
+\r
+  private String getLastCommonVersion(VcsRoot baseRoot, String baseVersion, VcsRoot tipRoot, String tipVersion) throws VcsException {\r
+    OperationContext context = createContext(tipRoot, "find fork version");\r
+    Settings baseSettings = context.getSettings(baseRoot);\r
+    Settings tipSettings = context.getSettings();\r
+    LOG.debug("Find last common version between [" + baseSettings.debugInfo() + "-" + baseVersion + "].." +\r
+              "[" + tipSettings.debugInfo() + "-" + tipVersion + "]");\r
+    RevWalk walk = null;\r
+    try {\r
+      RevCommit baseCommit = ensureCommitLoaded(context, baseSettings, baseVersion);\r
+      RevCommit tipCommit = ensureCommitLoaded(context, tipSettings, tipVersion);\r
+      Repository tipRepository = context.getRepository(tipSettings);\r
+      walk = new RevWalk(tipRepository);\r
+      walk.setRevFilter(RevFilter.MERGE_BASE);\r
+      walk.markStart(walk.parseCommit(baseCommit.getId()));\r
+      walk.markStart(walk.parseCommit(tipCommit.getId()));\r
+      final RevCommit base = walk.next();\r
+      String result = GitServerUtil.makeVersion(base);\r
+      LOG.debug("Last common revision between " + baseSettings.debugInfo() + " and " + tipSettings.debugInfo() + " is " + result);\r
+      return result;\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      try {\r
+        if (walk != null)\r
+          walk.release();\r
+      } finally {\r
+        context.close();\r
+      }\r
+    }\r
+  }\r
+\r
+\r
+  public void buildPatch(@NotNull VcsRoot root,\r
+                         @Nullable final String fromVersion,\r
+                         @NotNull String toVersion,\r
+                         @NotNull final PatchBuilder builder,\r
+                         @NotNull CheckoutRules checkoutRules) throws IOException, VcsException {\r
+    final OperationContext context = createContext(root, "patch building");\r
+    final boolean debugFlag = LOG.isDebugEnabled();\r
+    final boolean debugInfoOnEachCommit = myConfig.isPrintDebugInfoOnEachCommit();\r
+    try {\r
+      final Repository r = context.getRepository();\r
+      VcsChangeTreeWalk tw = null;\r
+      try {\r
+        RevCommit toCommit = ensureRevCommitLoaded(context, context.getSettings(), GitUtils.versionRevision(toVersion));\r
+        if (toCommit == null) {\r
+          throw new VcsException("Missing commit for version: " + toVersion);\r
+        }\r
+        tw = new VcsChangeTreeWalk(r, context.getSettings().debugInfo());\r
+        tw.setFilter(TreeFilter.ANY_DIFF);\r
+        tw.setRecursive(true);\r
+        context.addTree(tw, r, toCommit, false);\r
+        if (fromVersion != null) {\r
+          if (debugFlag) {\r
+            LOG.debug("Creating patch " + fromVersion + ".." + toVersion + " for " + context.getSettings().debugInfo());\r
+          }\r
+          RevCommit fromCommit = getCommit(r, GitUtils.versionRevision(fromVersion));\r
+          if (fromCommit == null) {\r
+            throw new IncrementalPatchImpossibleException("The form commit " + fromVersion + " is not available in the repository");\r
+          }\r
+          context.addTree(tw, r, fromCommit, true);\r
+        } else {\r
+          if (debugFlag) {\r
+            LOG.debug("Creating clean patch " + toVersion + " for " + context.getSettings().debugInfo());\r
+          }\r
+          tw.addTree(new EmptyTreeIterator());\r
+        }\r
+        final List<Callable<Void>> actions = new LinkedList<Callable<Void>>();\r
+        while (tw.next()) {\r
+          final String path = tw.getPathString();\r
+          final String mapped = checkoutRules.map(path);\r
+          if (mapped == null) {\r
+            continue;\r
+          }\r
+          if (debugFlag && debugInfoOnEachCommit) {\r
+            LOG.debug("File found " + tw.treeWalkInfo(path) + " for " + context.getSettings().debugInfo());\r
+          }\r
+          switch (tw.classifyChange()) {\r
+            case UNCHANGED:\r
+              // change is ignored\r
+              continue;\r
+            case MODIFIED:\r
+            case ADDED:\r
+            case FILE_MODE_CHANGED:\r
+              if (!FileMode.GITLINK.equals(tw.getFileMode(0))) {\r
+                final String mode = tw.getModeDiff();\r
+                if (mode != null && LOG.isDebugEnabled())\r
+                  LOG.debug("The mode change " + mode + " is detected for " + tw.treeWalkInfo(path));\r
+                final ObjectId id = tw.getObjectId(0);\r
+                final Repository objRep = getRepository(r, tw, 0);\r
+                final Callable<Void> action = new Callable<Void>() {\r
+                  public Void call() throws Exception {\r
+                    InputStream objectStream = null;\r
+                    try {\r
+                      final ObjectLoader loader = objRep.open(id);\r
+                      if (loader == null) {\r
+                        throw new IOException("Unable to find blob " + id + (path == null ? "" : "(" + path + ")") + " in repository " + r);\r
+                      }\r
+                      objectStream = loader.isLarge() ? loader.openStream() : new ByteArrayInputStream(loader.getCachedBytes());\r
+                      builder.changeOrCreateBinaryFile(GitUtils.toFile(mapped), mode, objectStream, loader.getSize());\r
+                    } catch (Error e) {\r
+                      LOG.error("Unable to load file: " + path + "(" + id.name() + ") from: " + context.getSettings().debugInfo());\r
+                      throw e;\r
+                    } catch (Exception e) {\r
+                      LOG.error("Unable to load file: " + path + "(" + id.name() + ") from: " + context.getSettings().debugInfo());\r
+                      throw e;\r
+                    } finally {\r
+                      if (objectStream != null) objectStream.close();\r
+                    }\r
+                    return null;\r
+                  }\r
+                };\r
+                if (fromVersion == null) {\r
+                  // clean patch, we aren't going to see any deletes\r
+                  action.call();\r
+                } else {\r
+                  actions.add(action);\r
+                }\r
+              }\r
+              break;\r
+            case DELETED:\r
+              if (!FileMode.GITLINK.equals(tw.getFileMode(0))) {\r
+                builder.deleteFile(GitUtils.toFile(mapped), true);\r
+              }\r
+              break;\r
+            default:\r
+              throw new IllegalStateException("Unknown change type");\r
+          }\r
+        }\r
+        for (Callable<Void> a : actions) {\r
+          a.call();\r
+        }\r
+      } finally {\r
+        if (tw != null) tw.release();\r
+      }\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+\r
+  @NotNull\r
+  public byte[] getContent(@NotNull VcsModification vcsModification,\r
+                           @NotNull VcsChangeInfo change,\r
+                           @NotNull VcsChangeInfo.ContentType contentType,\r
+                           @NotNull VcsRoot vcsRoot)\r
+    throws VcsException {\r
+    String version = contentType == VcsChangeInfo.ContentType.BEFORE_CHANGE\r
+                     ? change.getBeforeChangeRevisionNumber()\r
+                     : change.getAfterChangeRevisionNumber();\r
+    String file = change.getRelativeFileName();\r
+    return getContent(file, vcsRoot, version);\r
+  }\r
+\r
+  @NotNull\r
+  public byte[] getContent(@NotNull String filePath, @NotNull VcsRoot root, @NotNull String version) throws VcsException {\r
+    OperationContext context = createContext(root, "retrieving content");\r
+    try {\r
+      final long start = System.currentTimeMillis();\r
+      Repository r = context.getRepository();\r
+      final TreeWalk tw = new TreeWalk(r);\r
+      try {\r
+        if (LOG.isDebugEnabled()) {\r
+          LOG.debug("Getting data from " + version + ":" + filePath + " for " + context.getSettings().debugInfo());\r
+        }\r
+        final String rev = GitUtils.versionRevision(version);\r
+        RevCommit c = ensureRevCommitLoaded(context, context.getSettings(), rev);\r
+        tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(filePath)));\r
+        tw.setRecursive(tw.getFilter().shouldBeRecursive());\r
+        context.addTree(tw, r, c, true);\r
+        if (!tw.next()) {\r
+          throw new VcsFileNotFoundException("The file " + filePath + " could not be found in " + rev + context.getSettings().debugInfo());\r
+        }\r
+        final byte[] data = loadObject(r, tw, 0);\r
+        if (LOG.isDebugEnabled()) {\r
+          LOG.debug(\r
+            "File retrieved " + version + ":" + filePath + " (hash = " + tw.getObjectId(0) + ", length = " + data.length + ") for " +\r
+            context.getSettings().debugInfo());\r
+        }\r
+        return data;\r
+      } finally {\r
+        final long finish = System.currentTimeMillis();\r
+        if (PERFORMANCE_LOG.isDebugEnabled()) {\r
+          PERFORMANCE_LOG.debug("[getContent] root=" + context.getSettings().debugInfo() + ", file=" + filePath + ", get object content: " + (finish - start) + "ms");\r
+        }\r
+        tw.release();\r
+      }\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Load bytes that correspond to the position in the tree walker\r
+   *\r
+   * @param r   the initial repository\r
+   * @param tw  the tree walker\r
+   * @param nth the tree in the tree wailer\r
+   * @return loaded bytes\r
+   * @throws IOException if there is an IO error\r
+   */\r
+  private byte[] loadObject(Repository r, TreeWalk tw, final int nth) throws IOException {\r
+    ObjectId id = tw.getObjectId(nth);\r
+    Repository objRep = getRepository(r, tw, nth);\r
+    final String path = tw.getPathString();\r
+    return loadObject(objRep, path, id);\r
+  }\r
+\r
+  /**\r
+   * Load object by blob ID\r
+   *\r
+   * @param r    the repository\r
+   * @param path the path (might be null)\r
+   * @param id   the object id\r
+   * @return the object's bytes\r
+   * @throws IOException in case of IO problem\r
+   */\r
+  private byte[] loadObject(Repository r, String path, ObjectId id) throws IOException {\r
+    final ObjectLoader loader = r.open(id);\r
+    if (loader == null) {\r
+      throw new IOException("Unable to find blob " + id + (path == null ? "" : "(" + path + ")") + " in repository " + r);\r
+    }\r
+    if (loader.isLarge()) {\r
+      assert loader.getSize() < Integer.MAX_VALUE;\r
+      ByteArrayOutputStream output = new ByteArrayOutputStream((int) loader.getSize());\r
+      loader.copyTo(output);\r
+      return output.toByteArray();\r
+    } else {\r
+      return loader.getCachedBytes();\r
+    }\r
+  }\r
+\r
+  private RevCommit ensureCommitLoaded(OperationContext context, Settings rootSettings, String commitWithDate) throws Exception {\r
+    final String commit = GitUtils.versionRevision(commitWithDate);\r
+    return ensureRevCommitLoaded(context, rootSettings, commit);\r
+  }\r
+\r
+  private RevCommit ensureRevCommitLoaded(OperationContext context, Settings settings, String commitSHA) throws Exception {\r
+    Repository db = context.getRepository(settings);\r
+    RevCommit result = null;\r
+    try {\r
+      final long start = System.currentTimeMillis();\r
+      result = getCommit(db, commitSHA);\r
+      final long finish = System.currentTimeMillis();\r
+      if (PERFORMANCE_LOG.isDebugEnabled()) {\r
+        PERFORMANCE_LOG.debug("[ensureCommitLoaded] root=" + settings.debugInfo() + ", commit=" + commitSHA + ", local commit lookup: " + (finish - start) + "ms");\r
+      }\r
+    } catch (IOException ex) {\r
+      if (LOG.isDebugEnabled()) {\r
+        LOG.debug("IO problem for commit " + commitSHA + " in " + settings.debugInfo(), ex);\r
+      }\r
+    }\r
+    if (result == null) {\r
+      if (LOG.isDebugEnabled()) {\r
+        LOG.debug("Commit " + commitSHA + " is not in the repository for " + settings.debugInfo() + ", fetching data... ");\r
+      }\r
+      fetchBranchData(settings, db);\r
+      result = getCommit(db, commitSHA);\r
+      if (result == null) {\r
+        throw new VcsException("The version name could not be resolved " + commitSHA + "(" + settings.getRepositoryFetchURL().toString() + "#" + settings.getRef() + ")");\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  RevCommit getCommit(Repository repository, String commitSHA) throws IOException {\r
+    return getCommit(repository, ObjectId.fromString(commitSHA));\r
+  }\r
+\r
+  public RevCommit getCommit(Repository repository, ObjectId commitId) throws IOException {\r
+    final long start = System.currentTimeMillis();\r
+    RevWalk walk = new RevWalk(repository);\r
+    try {\r
+      return walk.parseCommit(commitId);\r
+    } finally {\r
+      walk.release();\r
+      final long finish = System.currentTimeMillis();\r
+      if (PERFORMANCE_LOG.isDebugEnabled()) {\r
+        PERFORMANCE_LOG.debug("[RevWalk.parseCommit] repository=" + repository.getDirectory().getAbsolutePath() + ", commit=" + commitId.name() + ", took: " + (finish - start) + "ms");\r
+      }\r
+    }\r
+  }\r
+\r
+  @NotNull\r
+  public String getName() {\r
+    return Constants.VCS_NAME;\r
+  }\r
+\r
+  @NotNull\r
+  public String getDisplayName() {\r
+    initDisplayNameIfRequired();\r
+    return myDisplayName;\r
+  }\r
+\r
+  private void initDisplayNameIfRequired() {\r
+    if (myDisplayName == null) {\r
+      if (myExtensionHolder != null) {\r
+        boolean communityPluginFound = false;\r
+        final Collection<VcsSupportContext> vcsPlugins = myExtensionHolder.getServices(VcsSupportContext.class);\r
+        for (VcsSupportContext plugin : vcsPlugins) {\r
+          if (plugin.getCore().getName().equals("git")) {\r
+            communityPluginFound = true;\r
+          }\r
+        }\r
+        if (communityPluginFound) {\r
+          myDisplayName = "Git (Jetbrains plugin)";\r
+        } else {\r
+          myDisplayName = "Git";\r
+        }\r
+      } else {\r
+        myDisplayName = "Git (Jetbrains plugin)";\r
+      }\r
+    }\r
+  }\r
+\r
+  public PropertiesProcessor getVcsPropertiesProcessor() {\r
+    return new VcsPropertiesProcessor();\r
+  }\r
+\r
+  @NotNull\r
+  public String getVcsSettingsJspFilePath() {\r
+    return "gitSettings.jsp";\r
+  }\r
+\r
+  @NotNull\r
+  public String describeVcsRoot(VcsRoot root) {\r
+    final String branch = root.getProperty(Constants.BRANCH_NAME);\r
+    return root.getProperty(Constants.FETCH_URL) + "#" + (branch == null ? "master" : branch);\r
+  }\r
+\r
+  public Map<String, String> getDefaultVcsProperties() {\r
+    final HashMap<String, String> map = new HashMap<String, String>();\r
+    map.put(Constants.BRANCH_NAME, "master");\r
+    map.put(Constants.IGNORE_KNOWN_HOSTS, "true");\r
+    return map;\r
+  }\r
+\r
+  public String getVersionDisplayName(@NotNull String version, @NotNull VcsRoot root) throws VcsException {\r
+    return GitServerUtil.displayVersion(version);\r
+  }\r
+\r
+  @NotNull\r
+  public Comparator<String> getVersionComparator() {\r
+    return GitUtils.VERSION_COMPARATOR;\r
+  }\r
+\r
+  @NotNull\r
+  public String getCurrentVersion(@NotNull VcsRoot root) throws VcsException {\r
+    OperationContext context = createContext(root, "retrieving current version");\r
+    Settings s = context.getSettings();\r
+    try {\r
+      Repository r = context.getRepository();\r
+      String refName = GitUtils.expandRef(s.getRef());\r
+\r
+      if (!myConfig.isSeparateProcessForFetch() || isRemoteRefUpdated(root, r, s, refName))\r
+        fetchBranchData(s, r);\r
+\r
+      Ref branchRef = r.getRef(refName);\r
+      if (branchRef == null) {\r
+        throw new VcsException("The ref '" + refName + "' could not be resolved");\r
+      }\r
+      String cachedCurrentVersion = getCachedCurrentVersion(s.getRepositoryDir(), s.getRef());\r
+      if (cachedCurrentVersion != null && GitUtils.versionRevision(cachedCurrentVersion).equals(branchRef.getObjectId().name())) {\r
+        return cachedCurrentVersion;\r
+      } else {\r
+        RevCommit c = getCommit(r, branchRef.getObjectId());\r
+        if (c == null) {\r
+          throw new VcsException("The ref '" + refName + "' could not be resolved");\r
+        }\r
+        if (LOG.isDebugEnabled()) {\r
+          LOG.debug("Current version: " + c.getId().name() + " " + s.debugInfo());\r
+        }\r
+        final String currentVersion = GitServerUtil.makeVersion(c);\r
+        setCachedCurrentVersion(s.getRepositoryDir(), s.getRef(), currentVersion);\r
+        GitMapFullPath.invalidateRevisionsCache(root);\r
+        return currentVersion;\r
+      }\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+\r
+  private boolean isRemoteRefUpdated(@NotNull VcsRoot root, @NotNull Repository db, @NotNull Settings s, @NotNull String refName) throws Exception {\r
+    Map<String, Ref> remoteRefs = getRemoteRefs(root, db, s);\r
+    Ref remoteRef = remoteRefs.get(refName);\r
+    if (remoteRef == null)\r
+      return true;\r
+\r
+    String cachedCurrentVersion = getCachedCurrentVersion(s.getRepositoryDir(), s.getRef());\r
+    return cachedCurrentVersion == null || !remoteRef.getObjectId().name().equals(GitUtils.versionRevision(cachedCurrentVersion));\r
+  }\r
+\r
+\r
+  /**\r
+   * Return cached current version for branch in repository in specified dir, or null if no cache version found.\r
+   */\r
+  private String getCachedCurrentVersion(File repositoryDir, String branchName) {\r
+    return myCurrentVersionCache.get(Pair.create(repositoryDir, branchName));\r
+  }\r
+\r
+  /**\r
+   * Save current version for branch of repository in cache.\r
+   */\r
+  private void setCachedCurrentVersion(File repositoryDir, String branchName, String currentVersion) {\r
+    myCurrentVersionCache.put(Pair.create(repositoryDir, branchName), currentVersion);\r
+  }\r
+\r
+  public boolean sourcesUpdatePossibleIfChangesNotFound(@NotNull VcsRoot root) {\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Fetch data for the branch\r
+   *\r
+   * @param settings   settings for the root\r
+   * @param repository the repository\r
+   * @throws Exception if there is a problem with fetching data\r
+   */\r
+  private void fetchBranchData(Settings settings, Repository repository) throws Exception {\r
+    final String refName = GitUtils.expandRef(settings.getRef());\r
+    RefSpec spec = new RefSpec().setSource(refName).setDestination(refName).setForceUpdate(true);\r
+    fetch(repository, settings.getRepositoryFetchURL(), spec, settings.getAuthSettings());\r
+  }\r
+\r
+\r
+  public void fetch(Repository db, URIish fetchURI, Collection<RefSpec> refspecs, Settings.AuthSettings auth) throws NotSupportedException, VcsException, TransportException {\r
+    File repositoryDir = db.getDirectory();\r
+    assert repositoryDir != null : "Non-local repository";\r
+    Lock rmLock = myRepositoryManager.getRmLock(repositoryDir).readLock();\r
+    rmLock.lock();\r
+    try {\r
+      final long start = System.currentTimeMillis();\r
+      synchronized (myRepositoryManager.getWriteLock(repositoryDir)) {\r
+        final long finish = System.currentTimeMillis();\r
+        PERFORMANCE_LOG.debug("[waitForWriteLock] repository: " + repositoryDir.getAbsolutePath() + ", took " + (finish - start) + "ms");\r
+        myFetchCommand.fetch(db, fetchURI, refspecs, auth);\r
+      }\r
+    } finally {\r
+      rmLock.unlock();\r
+    }\r
+  }\r
+  /**\r
+   * Make fetch into local repository (it.s getDirectory() should be != null)\r
+   *\r
+   * @param db repository\r
+   * @param fetchURI uri to fetch\r
+   * @param refspec refspec\r
+   * @param auth auth settings\r
+   */\r
+  public void fetch(Repository db, URIish fetchURI, RefSpec refspec, Settings.AuthSettings auth) throws NotSupportedException, VcsException, TransportException {\r
+    fetch(db, fetchURI, Collections.singletonList(refspec), auth);\r
+  }\r
+\r
+\r
+  public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException {\r
+    OperationContext context = createContext(vcsRoot, "connection test");\r
+    TestConnectionCommand command = new TestConnectionCommand(myTransportFactory, myRepositoryManager);\r
+    try {\r
+      return command.testConnection(context);\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+\r
+  @Override\r
+  public TestConnectionSupport getTestConnectionSupport() {\r
+    return this;\r
+  }\r
+\r
+  public OperationContext createContext(VcsRoot root, String operation) {\r
+    return new OperationContext(this, myRepositoryManager, root, operation);\r
+  }\r
+\r
+  public LabelingSupport getLabelingSupport() {\r
+    return this;\r
+  }\r
+\r
+  @NotNull\r
+  public VcsFileContentProvider getContentProvider() {\r
+    return this;\r
+  }\r
+\r
+  @NotNull\r
+  public CollectChangesPolicy getCollectChangesPolicy() {\r
+    return this;\r
+  }\r
+\r
+  @NotNull\r
+  public BuildPatchPolicy getBuildPatchPolicy() {\r
+    return this;\r
+  }\r
+\r
+  public String label(@NotNull String label, @NotNull String version, @NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules)\r
+    throws VcsException {\r
+    OperationContext context = createContext(root, "labelling");\r
+    Settings s = context.getSettings();\r
+    try {\r
+      Repository r = context.getRepository();\r
+      String commitSHA = GitUtils.versionRevision(version);\r
+      RevCommit commit = ensureRevCommitLoaded(context, s, commitSHA);\r
+      Git git = new Git(r);\r
+      git.tag().setName(label).setObjectId(commit).call();\r
+      String tagRef = GitUtils.tagName(label);\r
+      if (LOG.isDebugEnabled()) {\r
+        LOG.debug("Tag created  " + label + "=" + version + " for " + s.debugInfo());\r
+      }\r
+      synchronized (myRepositoryManager.getWriteLock(s.getRepositoryDir())) {\r
+        final Transport tn = myTransportFactory.createTransport(r, s.getRepositoryPushURL(), s.getAuthSettings());\r
+        try {\r
+          final PushConnection c = tn.openPush();\r
+          try {\r
+            RemoteRefUpdate ru = new RemoteRefUpdate(r, tagRef, tagRef, false, null, null);\r
+            c.push(NullProgressMonitor.INSTANCE, Collections.singletonMap(tagRef, ru));\r
+            LOG.info("Tag  " + label + "=" + version + " pushed with status " + ru.getStatus() + " for " + s.debugInfo());\r
+            switch (ru.getStatus()) {\r
+              case UP_TO_DATE:\r
+              case OK:\r
+                break;\r
+              default:\r
+                throw new VcsException("The remote tag was not created (" + ru.getStatus() + "): " + label);\r
+            }\r
+          } finally {\r
+            c.close();\r
+          }\r
+          return label;\r
+        } finally {\r
+          tn.close();\r
+        }\r
+      }\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Get repository from tree walker\r
+   *\r
+   * @param r   the initial repository\r
+   * @param tw  the tree walker\r
+   * @param nth the position\r
+   * @return the actual repository\r
+   */\r
+  private Repository getRepository(Repository r, TreeWalk tw, int nth) {\r
+    Repository objRep;\r
+    AbstractTreeIterator ti = tw.getTree(nth, AbstractTreeIterator.class);\r
+    if (ti instanceof SubmoduleAwareTreeIterator) {\r
+      objRep = ((SubmoduleAwareTreeIterator)ti).getRepository();\r
+    } else {\r
+      objRep = r;\r
+    }\r
+    return objRep;\r
+  }\r
+\r
+  @Override\r
+  public VcsPersonalSupport getPersonalSupport() {\r
+    return this;\r
+  }\r
+\r
+  /**\r
+   * Expected fullPath format:\r
+   * <p/>\r
+   * "<git revision hash>|<repository url>|<file relative path>"\r
+   *\r
+   * @param rootEntry indicates the association between VCS root and build configuration\r
+   * @param fullPath  change path from IDE patch\r
+   * @return the mapped path\r
+   */\r
+  @NotNull\r
+  public Collection<String> mapFullPath(@NotNull final VcsRootEntry rootEntry, @NotNull final String fullPath) {\r
+    OperationContext context = createContext(rootEntry.getVcsRoot(), "map full path");\r
+    try {\r
+      return new GitMapFullPath(context, this, rootEntry, fullPath).mapFullPath();\r
+    } catch (VcsException e) {\r
+      LOG.error(e);\r
+      return Collections.emptySet();\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+  @Override\r
+  public boolean isAgentSideCheckoutAvailable() {\r
+    return true;\r
+  }\r
+\r
+\r
+  @Override\r
+  public UrlSupport getUrlSupport() {\r
+    return new GitUrlSupport();\r
+  }\r
+\r
+\r
+  public List<String> getRemoteBranches(@NotNull final VcsRoot root, @NotNull final String pattern) throws VcsException {\r
+    Collection<Ref> remotes = getRemoteRefs(root).values();\r
+    Pattern p = Pattern.compile(pattern);\r
+    List<String> result = new ArrayList<String>();\r
+    for (Ref ref : remotes) {\r
+      if (p.matcher(ref.getName()).matches()) {\r
+        result.add(ref.getName());\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  @NotNull\r
+  private Map<String, Ref> getRemoteRefs(@NotNull final VcsRoot root) throws VcsException {\r
+    OperationContext context = createContext(root, "list remote refs");\r
+    Settings s = context.getSettings();\r
+    File tmpDir = null;\r
+    try {\r
+      tmpDir = FileUtil.createTempDirectory("git-ls-remote", "");\r
+      s.setUserDefinedRepositoryPath(tmpDir);\r
+      Repository db = context.getRepository();\r
+      return getRemoteRefs(root, db, s);\r
+    } catch (Exception e) {\r
+      throw context.wrapException(e);\r
+    } finally {\r
+      context.close();\r
+      if (tmpDir != null) {\r
+        myRepositoryManager.cleanLocksFor(tmpDir);\r
+        FileUtil.delete(tmpDir);\r
+      }\r
+    }\r
+  }\r
+\r
+\r
+  @NotNull\r
+  private Map<String, Ref> getRemoteRefs(@NotNull final VcsRoot root, @NotNull Repository db, @NotNull Settings s) throws Exception {\r
+    Transport transport = null;\r
+    FetchConnection connection = null;\r
+    try {\r
+      transport = myTransportFactory.createTransport(db, s.getRepositoryFetchURL(), s.getAuthSettings());\r
+      connection = transport.openFetch();\r
+      return connection.getRefsMap();\r
+    } catch (NotSupportedException nse) {\r
+      throw friendlyNotSupportedException(root, s, nse);\r
+    } catch (TransportException te) {\r
+      throw friendlyTransportException(te);\r
+    } finally {\r
+      if (connection != null) connection.close();\r
+      if (transport != null) transport.close();\r
+    }\r
+  }\r
+\r
+  @NotNull\r
+  private ObjectId getVcsRootGitId(final @NotNull VcsRoot root) throws VcsException{\r
+    final OperationContext context = createContext(root, "client-mapping");\r
+    try {\r
+      final Settings gitSettings = context.getSettings(root);\r
+      final Repository gitRepo = context.getRepository(gitSettings);\r
+      if(gitRepo == null){\r
+        throw new VcsException(String.format("Could not find Git Repository for '%s'", root.getName()));\r
+      }\r
+      final ObjectId objectId = gitRepo.resolve(gitSettings.getRef());\r
+      if(objectId == null){\r
+        throw new VcsException(String.format("Could not resolve Git Reference '%s'", gitSettings.getRef()));\r
+      }\r
+      return objectId;\r
+    } catch (AmbiguousObjectException e) {\r
+      throw new VcsException(e);\r
+    } catch (IOException e) {\r
+      throw new VcsException(e);\r
+    } finally {\r
+      context.close();\r
+    }\r
+  }\r
+\r
+  public Collection<VcsClientMapping> getClientMapping(final @NotNull VcsRoot root, final @NotNull IncludeRule rule) throws VcsException {\r
+    final ObjectId gitObjId = getVcsRootGitId(root);\r
+    return Collections.singletonList(new VcsClientMapping(String.format("%s||%s", gitObjId.name(), rule.getFrom()), rule.getTo()));\r
+  }\r
+\r
+  @Override\r
+  public boolean isDAGBasedVcs() {\r
+    return true;\r
+  }\r
+}\r