@CheckForNull
 @Override
 protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener listener)
     throws IOException, InterruptedException {
   String cacheEntry = getCacheEntry();
   Lock cacheLock = getCacheLock(cacheEntry);
   cacheLock.lock();
   try {
     File cacheDir = getCacheDir(cacheEntry);
     Git git =
         Git.with(listener, new EnvVars(System.getenv()))
             .in(cacheDir)
             .using(GitTool.getDefaultInstallation().getGitExe());
     GitClient client = git.getClient();
     client.addDefaultCredentials(getCredentials());
     if (!client.hasGitRepo()) {
       listener.getLogger().println("Creating git repository in " + cacheDir);
       client.init();
     }
     String remoteName = getRemoteName();
     listener.getLogger().println("Setting " + remoteName + " to " + getRemote());
     client.setRemoteUrl(remoteName, getRemote());
     listener.getLogger().println("Fetching " + remoteName + "...");
     List<RefSpec> refSpecs = getRefSpecs();
     client.fetch(remoteName, refSpecs.toArray(new RefSpec[refSpecs.size()]));
     // we don't prune remotes here, as we just want one head's revision
     for (Branch b : client.getRemoteBranches()) {
       String branchName = StringUtils.removeStart(b.getName(), remoteName + "/");
       if (branchName.equals(head.getName())) {
         return new SCMRevisionImpl(head, b.getSHA1String());
       }
     }
     return null;
   } finally {
     cacheLock.unlock();
   }
 }
  @NonNull
  @Override
  protected void retrieve(@NonNull final SCMHeadObserver observer, @NonNull TaskListener listener)
      throws IOException, InterruptedException {
    String cacheEntry = getCacheEntry();
    Lock cacheLock = getCacheLock(cacheEntry);
    cacheLock.lock();
    try {
      File cacheDir = getCacheDir(cacheEntry);
      Git git =
          Git.with(listener, new EnvVars(System.getenv()))
              .in(cacheDir)
              .using(GitTool.getDefaultInstallation().getGitExe());
      GitClient client = git.getClient();
      client.addDefaultCredentials(getCredentials());
      if (!client.hasGitRepo()) {
        listener.getLogger().println("Creating git repository in " + cacheDir);
        client.init();
      }
      String remoteName = getRemoteName();
      listener.getLogger().println("Setting " + remoteName + " to " + getRemote());
      client.setRemoteUrl(remoteName, getRemote());
      listener.getLogger().println("Fetching " + remoteName + "...");
      List<RefSpec> refSpecs = getRefSpecs();
      client.fetch(remoteName, refSpecs.toArray(new RefSpec[refSpecs.size()]));
      listener.getLogger().println("Pruning stale remotes...");
      final Repository repository = client.getRepository();
      try {
        client.prune(new RemoteConfig(repository.getConfig(), remoteName));
      } catch (UnsupportedOperationException e) {
        e.printStackTrace(listener.error("Could not prune stale remotes"));
      } catch (URISyntaxException e) {
        e.printStackTrace(listener.error("Could not prune stale remotes"));
      }
      listener.getLogger().println("Getting remote branches...");
      SCMSourceCriteria branchCriteria = getCriteria();
      RevWalk walk = new RevWalk(repository);
      try {
        walk.setRetainBody(false);
        for (Branch b : client.getRemoteBranches()) {
          if (!b.getName().startsWith(remoteName + "/")) {
            continue;
          }
          final String branchName = StringUtils.removeStart(b.getName(), remoteName + "/");
          listener.getLogger().println("Checking branch " + branchName);
          if (isExcluded(branchName)) {
            continue;
          }
          if (branchCriteria != null) {
            RevCommit commit = walk.parseCommit(b.getSHA1());
            final long lastModified = TimeUnit.SECONDS.toMillis(commit.getCommitTime());
            final RevTree tree = commit.getTree();
            SCMSourceCriteria.Probe probe =
                new SCMSourceCriteria.Probe() {
                  @Override
                  public String name() {
                    return branchName;
                  }

                  @Override
                  public long lastModified() {
                    return lastModified;
                  }

                  @Override
                  public boolean exists(@NonNull String path) throws IOException {
                    TreeWalk tw = TreeWalk.forPath(repository, path, tree);
                    try {
                      return tw != null;
                    } finally {
                      if (tw != null) {
                        tw.release();
                      }
                    }
                  }
                };
            if (branchCriteria.isHead(probe, listener)) {
              listener.getLogger().println("Met criteria");
            } else {
              listener.getLogger().println("Does not meet criteria");
              continue;
            }
          }
          SCMHead head = new SCMHead(branchName);
          SCMRevision hash = new SCMRevisionImpl(head, b.getSHA1String());
          observer.observe(head, hash);
          if (!observer.isObserving()) {
            return;
          }
        }
      } finally {
        walk.dispose();
      }

      listener.getLogger().println("Done.");
    } finally {
      cacheLock.unlock();
    }
  }