1 /* 2 * Copyright (C) 2011-2012, Robin Stocker <robin@nibor.org> and others 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Distribution License v. 1.0 which is available at 6 * https://www.eclipse.org/org/documents/edl-v10.php. 7 * 8 * SPDX-License-Identifier: BSD-3-Clause 9 */ 10 11 package org.eclipse.jgit.revwalk; 12 13 import java.io.IOException; 14 import java.util.ArrayList; 15 import java.util.Collection; 16 import java.util.List; 17 18 import org.eclipse.jgit.errors.IncorrectObjectTypeException; 19 import org.eclipse.jgit.errors.MissingObjectException; 20 import org.eclipse.jgit.internal.JGitText; 21 import org.eclipse.jgit.lib.NullProgressMonitor; 22 import org.eclipse.jgit.lib.ProgressMonitor; 23 import org.eclipse.jgit.lib.Ref; 24 25 /** 26 * Utility methods for {@link org.eclipse.jgit.revwalk.RevWalk}. 27 */ 28 public final class RevWalkUtils { 29 30 private RevWalkUtils() { 31 // Utility class 32 } 33 34 /** 35 * Count the number of commits that are reachable from <code>start</code> 36 * until a commit that is reachable from <code>end</code> is encountered. In 37 * other words, count the number of commits that are in <code>start</code>, 38 * but not in <code>end</code>. 39 * <p> 40 * Note that this method calls 41 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 42 * note that the existing rev filter on the walk is left as-is, so be sure 43 * to set the right rev filter before calling this method. 44 * 45 * @param walk 46 * the rev walk to use 47 * @param start 48 * the commit to start counting from 49 * @param end 50 * the commit where counting should end, or null if counting 51 * should be done until there are no more commits 52 * @return the number of commits 53 * @throws org.eclipse.jgit.errors.MissingObjectException 54 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 55 * @throws java.io.IOException 56 */ 57 public static int count(final RevWalk walk, final RevCommit start, 58 final RevCommit end) throws MissingObjectException, 59 IncorrectObjectTypeException, IOException { 60 return find(walk, start, end).size(); 61 } 62 63 /** 64 * Find commits that are reachable from <code>start</code> until a commit 65 * that is reachable from <code>end</code> is encountered. In other words, 66 * Find of commits that are in <code>start</code>, but not in 67 * <code>end</code>. 68 * <p> 69 * Note that this method calls 70 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. Also 71 * note that the existing rev filter on the walk is left as-is, so be sure 72 * to set the right rev filter before calling this method. 73 * 74 * @param walk 75 * the rev walk to use 76 * @param start 77 * the commit to start counting from 78 * @param end 79 * the commit where counting should end, or null if counting 80 * should be done until there are no more commits 81 * @return the commits found 82 * @throws org.eclipse.jgit.errors.MissingObjectException 83 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 84 * @throws java.io.IOException 85 */ 86 public static List<RevCommit> find(final RevWalk walk, 87 final RevCommit start, final RevCommit end) 88 throws MissingObjectException, IncorrectObjectTypeException, 89 IOException { 90 walk.reset(); 91 walk.markStart(start); 92 if (end != null) 93 walk.markUninteresting(end); 94 95 List<RevCommit> commits = new ArrayList<>(); 96 for (RevCommit c : walk) 97 commits.add(c); 98 return commits; 99 } 100 101 /** 102 * Find the list of branches a given commit is reachable from when following 103 * parents. 104 * <p> 105 * Note that this method calls 106 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. 107 * <p> 108 * In order to improve performance this method assumes clock skew among 109 * committers is never larger than 24 hours. 110 * 111 * @param commit 112 * the commit we are looking at 113 * @param revWalk 114 * The RevWalk to be used. 115 * @param refs 116 * the set of branches we want to see reachability from 117 * @return the list of branches a given commit is reachable from 118 * @throws org.eclipse.jgit.errors.MissingObjectException 119 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 120 * @throws java.io.IOException 121 */ 122 public static List<Ref> findBranchesReachableFrom(RevCommit commit, 123 RevWalk revWalk, Collection<Ref> refs) 124 throws MissingObjectException, IncorrectObjectTypeException, 125 IOException { 126 return findBranchesReachableFrom(commit, revWalk, refs, 127 NullProgressMonitor.INSTANCE); 128 } 129 130 /** 131 * Find the list of branches a given commit is reachable from when following 132 * parents. 133 * <p> 134 * Note that this method calls 135 * {@link org.eclipse.jgit.revwalk.RevWalk#reset()} at the beginning. 136 * <p> 137 * In order to improve performance this method assumes clock skew among 138 * committers is never larger than 24 hours. 139 * 140 * @param commit 141 * the commit we are looking at 142 * @param revWalk 143 * The RevWalk to be used. 144 * @param refs 145 * the set of branches we want to see reachability from 146 * @param monitor 147 * the callback for progress and cancellation 148 * @return the list of branches a given commit is reachable from 149 * @throws org.eclipse.jgit.errors.MissingObjectException 150 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException 151 * @throws java.io.IOException 152 * @since 5.4 153 */ 154 public static List<Ref> findBranchesReachableFrom(RevCommit commit, 155 RevWalk revWalk, Collection<Ref> refs, ProgressMonitor monitor) 156 throws MissingObjectException, IncorrectObjectTypeException, 157 IOException { 158 159 // Make sure commit is from the same RevWalk 160 commit = revWalk.parseCommit(commit.getId()); 161 revWalk.reset(); 162 List<Ref> filteredRefs = new ArrayList<>(); 163 monitor.beginTask(JGitText.get().searchForReachableBranches, 164 refs.size()); 165 final int SKEW = 24*3600; // one day clock skew 166 167 for (Ref ref : refs) { 168 RevObject maybehead = revWalk.parseAny(ref.getObjectId()); 169 if (!(maybehead instanceof RevCommit)) 170 continue; 171 RevCommit headCommit = (RevCommit) maybehead; 172 173 // if commit is in the ref branch, then the tip of ref should be 174 // newer than the commit we are looking for. Allow for a large 175 // clock skew. 176 if (headCommit.getCommitTime() + SKEW < commit.getCommitTime()) 177 continue; 178 179 filteredRefs.add(ref); 180 } 181 List<Ref> result = revWalk.getMergedInto(commit, filteredRefs, monitor); 182 monitor.endTask(); 183 return result; 184 } 185 186 }