Beispiel #1
0
  // printout all commit messages in a given range -> use and reset an existing RevWalk
  private void printCommits(String outFile, RevWalk walk)
      throws IOException, NoHeadException, GitAPIException {

    PrintWriter pout = new PrintWriter(new FileWriter(outFile), true);
    RevCommit c = walk.next();
    while (c != null && !c.has(RevFlag.UNINTERESTING)) {
      pout.println(printCommit(c));
      c = walk.next();
    }
    walk.reset();
    pout.close();
  }
Beispiel #2
0
  public void markCleanMerges(
      final RevWalk rw,
      final RevFlag canMergeFlag,
      final CodeReviewCommit mergeTip,
      final Set<RevCommit> alreadyAccepted)
      throws IntegrationException {
    if (mergeTip == null) {
      // If mergeTip is null here, branchTip was null, indicating a new branch
      // at the start of the merge process. We also elected to merge nothing,
      // probably due to missing dependencies. Nothing was cleanly merged.
      //
      return;
    }

    try {
      rw.resetRetain(canMergeFlag);
      rw.sort(RevSort.TOPO);
      rw.sort(RevSort.REVERSE, true);
      rw.markStart(mergeTip);
      for (RevCommit c : alreadyAccepted) {
        rw.markUninteresting(c);
      }

      CodeReviewCommit c;
      while ((c = (CodeReviewCommit) rw.next()) != null) {
        if (c.getPatchsetId() != null) {
          c.setStatusCode(CommitMergeStatus.CLEAN_MERGE);
        }
      }
    } catch (IOException e) {
      throw new IntegrationException("Cannot mark clean merges", e);
    }
  }
Beispiel #3
0
 private static boolean isReachable(Repository repo, AnyObjectId id) throws IOException {
   try (RevWalk rw = new RevWalk(repo)) {
     for (Ref ref : repo.getAllRefs().values()) {
       rw.markStart(rw.parseCommit(ref.getObjectId()));
     }
     for (RevCommit next; (next = rw.next()) != null; ) {
       if (AnyObjectId.equals(next, id)) {
         return true;
       }
     }
   }
   return false;
 }
Beispiel #4
0
  /**
   * Create an iterator to walk the merge base of two commits.
   *
   * @param aIdx index of the first commit in {@link #sourceObjects}.
   * @param bIdx index of the second commit in {@link #sourceObjects}.
   * @return the new iterator
   * @throws IncorrectObjectTypeException one of the input objects is not a commit.
   * @throws IOException objects are missing or multiple merge bases were found.
   */
  protected AbstractTreeIterator mergeBase(final int aIdx, final int bIdx) throws IOException {
    if (sourceCommits[aIdx] == null)
      throw new IncorrectObjectTypeException(sourceObjects[aIdx], Constants.TYPE_COMMIT);
    if (sourceCommits[bIdx] == null)
      throw new IncorrectObjectTypeException(sourceObjects[bIdx], Constants.TYPE_COMMIT);

    walk.reset();
    walk.setRevFilter(RevFilter.MERGE_BASE);
    walk.markStart(sourceCommits[aIdx]);
    walk.markStart(sourceCommits[bIdx]);
    final RevCommit base = walk.next();
    if (base == null) return new EmptyTreeIterator();
    final RevCommit base2 = walk.next();
    if (base2 != null) {
      throw new IOException(
          MessageFormat.format(
              JGitText.get().multipleMergeBasesFor,
              sourceCommits[aIdx].name(),
              sourceCommits[bIdx].name(),
              base.name(),
              base2.name()));
    }
    return openTree(base.getTree());
  }
  private void markReachable(final Set<ObjectId> have, final int maxTime) throws IOException {
    for (final Ref r : local.getAllRefs().values()) {
      try {
        final RevCommit o = walk.parseCommit(r.getObjectId());
        o.add(REACHABLE);
        reachableCommits.add(o);
      } catch (IOException readError) {
        // If we cannot read the value of the ref skip it.
      }
    }

    for (final ObjectId id : have) {
      try {
        final RevCommit o = walk.parseCommit(id);
        o.add(REACHABLE);
        reachableCommits.add(o);
      } catch (IOException readError) {
        // If we cannot read the value of the ref skip it.
      }
    }

    if (maxTime > 0) {
      // Mark reachable commits until we reach maxTime. These may
      // wind up later matching up against things we want and we
      // can avoid asking for something we already happen to have.
      //
      final Date maxWhen = new Date(maxTime * 1000L);
      walk.sort(RevSort.COMMIT_TIME_DESC);
      walk.markStart(reachableCommits);
      walk.setRevFilter(CommitTimeRevFilter.after(maxWhen));
      for (; ; ) {
        final RevCommit c = walk.next();
        if (c == null) break;
        if (c.has(ADVERTISED) && !c.has(COMMON)) {
          // This is actually going to be a common commit, but
          // our peer doesn't know that fact yet.
          //
          c.add(COMMON);
          c.carry(COMMON);
          reachableCommits.add(c);
        }
      }
    }
  }
Beispiel #6
0
  /**
   * Configure the generator to compute reverse blame (history of deletes).
   *
   * <p>This method is expensive as it immediately runs a RevWalk over the history spanning the
   * expression {@code start..end} (end being more recent than start) and then performs the
   * equivalent operation as {@link #push(String, AnyObjectId)} to begin blame traversal from the
   * commit named by {@code start} walking forwards through history until {@code end} blaming line
   * deletions.
   *
   * <p>A reverse blame may produce multiple sources for the same result line, each of these is a
   * descendant commit that removed the line, typically this occurs when the same deletion appears
   * in multiple side branches such as due to a cherry-pick. Applications relying on reverse should
   * use {@link BlameResult} as it filters these duplicate sources and only remembers the first
   * (oldest) deletion.
   *
   * @param start oldest commit to traverse from. The result file will be loaded from this commit's
   *     tree.
   * @param end most recent commits to stop traversal at. Usually an active branch tip, tag, or
   *     HEAD.
   * @return {@code this}
   * @throws IOException the repository cannot be read.
   */
  public BlameGenerator reverse(AnyObjectId start, Collection<? extends ObjectId> end)
      throws IOException {
    initRevPool(true);

    ReverseCommit result = (ReverseCommit) revPool.parseCommit(start);
    if (!find(result, resultPath)) return this;

    revPool.markUninteresting(result);
    for (ObjectId id : end) revPool.markStart(revPool.parseCommit(id));

    while (revPool.next() != null) {
      // just pump the queue
    }

    ReverseCandidate c = new ReverseCandidate(result, resultPath);
    c.sourceBlob = idBuf.toObjectId();
    c.loadText(reader);
    c.regionList = new Region(0, 0, c.sourceText.size());
    remaining = c.sourceText.size();
    push(c);
    return this;
  }
  @Override
  public void execute() throws BuildException {
    if (_property == null) {
      throw new BuildException("Property attribute is required", getLocation());
    }

    if (_path == null) {
      throw new BuildException("Path attribute is required", getLocation());
    }

    File gitDir = PathUtil.getGitDir(_gitDir, getProject(), getLocation());

    String relativePath = PathUtil.toRelativePath(gitDir, _path);

    if (_useCache) {
      String hash = _hashes.get(relativePath);

      if (hash != null) {
        Project currentProject = getProject();

        currentProject.setNewProperty(_property, hash);

        return;
      }
    }

    try (Repository repository = RepositoryCache.open(FileKey.exact(gitDir, FS.DETECTED))) {

      RevWalk revWalk = new RevWalk(repository);

      revWalk.setRetainBody(false);

      revWalk.markStart(revWalk.parseCommit(repository.resolve(Constants.HEAD)));

      if (_ignoreFileName == null) {
        revWalk.setRevFilter(MaxCountRevFilter.create(1));
      } else {
        revWalk.setRevFilter(MaxCountRevFilter.create(2));
      }

      revWalk.setTreeFilter(
          AndTreeFilter.create(PathFilter.create(relativePath), TreeFilter.ANY_DIFF));

      RevCommit revCommit = revWalk.next();

      if (revCommit == null) {
        throw new IllegalStateException("Unable to find any commit under " + _path);
      }

      if (hasIgnoreFile(repository, revCommit, relativePath)) {
        RevCommit secondRevCommit = revWalk.next();

        if (secondRevCommit != null) {
          revCommit = secondRevCommit;
        }
      }

      Project currentProject = getProject();

      String hash = revCommit.name();

      currentProject.setNewProperty(_property, hash);

      if (_useCache) {
        _hashes.put(relativePath, hash);
      }

      revWalk.dispose();
    } catch (Exception e) {
      throw new BuildException("Unable to get head hash for path " + _path, e);
    }
  }
  private void negotiate(final ProgressMonitor monitor) throws IOException, CancelledException {
    final MutableObjectId ackId = new MutableObjectId();
    int resultsPending = 0;
    int havesSent = 0;
    int havesSinceLastContinue = 0;
    boolean receivedContinue = false;
    boolean receivedAck = false;

    if (statelessRPC) state.writeTo(out, null);

    negotiateBegin();
    SEND_HAVES:
    for (; ; ) {
      final RevCommit c = walk.next();
      if (c == null) break SEND_HAVES;

      pckOut.writeString("have " + c.getId().name() + "\n");
      havesSent++;
      havesSinceLastContinue++;

      if ((31 & havesSent) != 0) {
        // We group the have lines into blocks of 32, each marked
        // with a flush (aka end). This one is within a block so
        // continue with another have line.
        //
        continue;
      }

      if (monitor.isCancelled()) throw new CancelledException();

      pckOut.end();
      resultsPending++; // Each end will cause a result to come back.

      if (havesSent == 32 && !statelessRPC) {
        // On the first block we race ahead and try to send
        // more of the second block while waiting for the
        // remote to respond to our first block request.
        // This keeps us one block ahead of the peer.
        //
        continue;
      }

      READ_RESULT:
      for (; ; ) {
        final AckNackResult anr = pckIn.readACK(ackId);
        switch (anr) {
          case NAK:
            // More have lines are necessary to compute the
            // pack on the remote side. Keep doing that.
            //
            resultsPending--;
            break READ_RESULT;

          case ACK:
            // The remote side is happy and knows exactly what
            // to send us. There is no further negotiation and
            // we can break out immediately.
            //
            multiAck = MultiAck.OFF;
            resultsPending = 0;
            receivedAck = true;
            if (statelessRPC) state.writeTo(out, null);
            break SEND_HAVES;

          case ACK_CONTINUE:
          case ACK_COMMON:
          case ACK_READY:
            // The server knows this commit (ackId). We don't
            // need to send any further along its ancestry, but
            // we need to continue to talk about other parts of
            // our local history.
            //
            markCommon(walk.parseAny(ackId), anr);
            receivedAck = true;
            receivedContinue = true;
            havesSinceLastContinue = 0;
            break;
        }

        if (monitor.isCancelled()) throw new CancelledException();
      }

      if (statelessRPC) state.writeTo(out, null);

      if (receivedContinue && havesSinceLastContinue > MAX_HAVES) {
        // Our history must be really different from the remote's.
        // We just sent a whole slew of have lines, and it did not
        // recognize any of them. Avoid sending our entire history
        // to them by giving up early.
        //
        break SEND_HAVES;
      }
    }

    // Tell the remote side we have run out of things to talk about.
    //
    if (monitor.isCancelled()) throw new CancelledException();

    // When statelessRPC is true we should always leave SEND_HAVES
    // loop above while in the middle of a request. This allows us
    // to just write done immediately.
    //
    pckOut.writeString("done\n");
    pckOut.flush();

    if (!receivedAck) {
      // Apparently if we have never received an ACK earlier
      // there is one more result expected from the done we
      // just sent to the remote.
      //
      multiAck = MultiAck.OFF;
      resultsPending++;
    }

    READ_RESULT:
    while (resultsPending > 0 || multiAck != MultiAck.OFF) {
      final AckNackResult anr = pckIn.readACK(ackId);
      resultsPending--;
      switch (anr) {
        case NAK:
          // A NAK is a response to an end we queued earlier
          // we eat it and look for another ACK/NAK message.
          //
          break;

        case ACK:
          // A solitary ACK at this point means the remote won't
          // speak anymore, but is going to send us a pack now.
          //
          break READ_RESULT;

        case ACK_CONTINUE:
        case ACK_COMMON:
        case ACK_READY:
          // We will expect a normal ACK to break out of the loop.
          //
          multiAck = MultiAck.CONTINUE;
          break;
      }

      if (monitor.isCancelled()) throw new CancelledException();
    }
  }