|
15 | 15 | import hudson.plugins.git.Branch; |
16 | 16 | import hudson.plugins.git.GitException; |
17 | 17 | import hudson.plugins.git.IGitAPI; |
18 | | -import hudson.plugins.git.IndexEntry; |
19 | 18 | import hudson.plugins.git.Revision; |
20 | 19 |
|
21 | | - |
22 | 20 | import java.io.IOException; |
23 | 21 | import java.io.OutputStream; |
| 22 | +import java.text.MessageFormat; |
24 | 23 | import java.util.ArrayList; |
25 | 24 | import java.util.Collection; |
26 | 25 | import java.util.HashMap; |
27 | 26 | import java.util.HashSet; |
28 | | -import java.util.Iterator; |
29 | 27 | import java.util.List; |
30 | 28 | import java.util.Map; |
31 | 29 | import java.util.Set; |
| 30 | +import java.util.logging.Level; |
32 | 31 | import java.util.logging.Logger; |
33 | 32 |
|
34 | 33 | import org.eclipse.jgit.lib.ObjectId; |
| 34 | +import org.eclipse.jgit.revwalk.RevWalk; |
| 35 | +import org.eclipse.jgit.revwalk.filter.RevFilter; |
35 | 36 |
|
36 | 37 | public class GitUtils { |
37 | 38 | IGitAPI git; |
@@ -92,39 +93,78 @@ public Revision getRevisionForSHA1(ObjectId sha1) throws GitException, IOExcepti |
92 | 93 | /** |
93 | 94 | * Return a list of 'tip' branches (I.E. branches that aren't included entirely within another branch). |
94 | 95 | * |
95 | | - * @param git |
96 | | - * @return |
| 96 | + * @param revisions |
| 97 | + * @return filtered tip branches |
97 | 98 | */ |
98 | 99 | public Collection<Revision> filterTipBranches(Collection<Revision> revisions) { |
99 | 100 | // If we have 3 branches that we might want to build |
100 | 101 | // ----A--.---.--- B |
101 | 102 | // \-----C |
102 | 103 |
|
103 | 104 | // we only want (B) and (C), as (A) is an ancestor (old). |
104 | | - |
105 | | - List<Revision> l = new ArrayList<Revision>(revisions); |
106 | | - |
107 | | - OUTER: |
108 | | - for (int i=0; i<l.size(); i++) { |
109 | | - for (int j=i+1; j<l.size(); j++) { |
110 | | - Revision ri = l.get(i); |
111 | | - Revision rj = l.get(j); |
112 | | - ObjectId commonAncestor = git.mergeBase(ri.getSha1(), rj.getSha1()); |
113 | | - if (commonAncestor==null) continue; |
114 | | - |
115 | | - if (commonAncestor.equals(ri.getSha1())) { |
116 | | - LOGGER.fine("filterTipBranches: "+rj+" subsumes "+ri); |
117 | | - l.remove(i); |
118 | | - i--; |
119 | | - continue OUTER; |
120 | | - } |
121 | | - if (commonAncestor.equals(rj.getSha1())) { |
122 | | - LOGGER.fine("filterTipBranches: "+ri+" subsumes "+rj); |
123 | | - l.remove(j); |
124 | | - j--; |
| 105 | + final List<Revision> l = new ArrayList<Revision>(revisions); |
| 106 | + |
| 107 | + // Bypass any rev walks if only one branch or less |
| 108 | + if (l.size() <= 1) |
| 109 | + return l; |
| 110 | + |
| 111 | + final boolean log = LOGGER.isLoggable(Level.FINE); |
| 112 | + Revision revI; |
| 113 | + Revision revJ; |
| 114 | + ObjectId shaI; |
| 115 | + ObjectId shaJ; |
| 116 | + ObjectId commonAncestor; |
| 117 | + RevWalk walk = null; |
| 118 | + final long start = System.currentTimeMillis(); |
| 119 | + long calls = 0; |
| 120 | + if (log) |
| 121 | + LOGGER.fine(MessageFormat.format( |
| 122 | + "Computing merge base of {0} branches", l.size())); |
| 123 | + try { |
| 124 | + walk = new RevWalk(git.getRepository()); |
| 125 | + walk.setRetainBody(false); |
| 126 | + walk.setRevFilter(RevFilter.MERGE_BASE); |
| 127 | + for (int i = 0; i < l.size(); i++) |
| 128 | + for (int j = i + 1; j < l.size(); j++) { |
| 129 | + revI = l.get(i); |
| 130 | + revJ = l.get(j); |
| 131 | + shaI = revI.getSha1(); |
| 132 | + shaJ = revJ.getSha1(); |
| 133 | + |
| 134 | + walk.reset(); |
| 135 | + walk.markStart(walk.parseCommit(shaI)); |
| 136 | + walk.markStart(walk.parseCommit(shaJ)); |
| 137 | + commonAncestor = walk.next(); |
| 138 | + calls++; |
| 139 | + |
| 140 | + if (commonAncestor == null) |
| 141 | + continue; |
| 142 | + if (commonAncestor.equals(shaI)) { |
| 143 | + if (log) |
| 144 | + LOGGER.fine("filterTipBranches: " + revJ |
| 145 | + + " subsumes " + revI); |
| 146 | + l.remove(i); |
| 147 | + i--; |
| 148 | + break; |
| 149 | + } |
| 150 | + if (commonAncestor.equals(shaJ)) { |
| 151 | + if (log) |
| 152 | + LOGGER.fine("filterTipBranches: " + revI |
| 153 | + + " subsumes " + revJ); |
| 154 | + l.remove(j); |
| 155 | + j--; |
| 156 | + } |
125 | 157 | } |
126 | | - } |
| 158 | + } catch (IOException e) { |
| 159 | + throw new GitException("Error computing merge base", e); |
| 160 | + } finally { |
| 161 | + if (walk != null) |
| 162 | + walk.release(); |
127 | 163 | } |
| 164 | + if (log) |
| 165 | + LOGGER.fine(MessageFormat.format( |
| 166 | + "Computed {0} merge bases in {1} ms", calls, |
| 167 | + (System.currentTimeMillis() - start))); |
128 | 168 |
|
129 | 169 | return l; |
130 | 170 | } |
|
0 commit comments