1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.revwalk;
45
46 import java.io.IOException;
47 import java.text.MessageFormat;
48 import java.util.LinkedList;
49
50 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
51 import org.eclipse.jgit.errors.MissingObjectException;
52 import org.eclipse.jgit.internal.JGitText;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 class MergeBaseGenerator extends Generator {
71 private static final int PARSED = RevWalk.PARSED;
72
73 private static final int IN_PENDING = RevWalk.SEEN;
74
75 private static final int POPPED = RevWalk.TEMP_MARK;
76
77 private static final int MERGE_BASE = RevWalk.REWRITE;
78
79 private final RevWalk walker;
80
81 private final DateRevQueue pending;
82
83 private int branchMask;
84
85 private int recarryTest;
86
87 private int recarryMask;
88
89 private int mergeBaseAncestor = -1;
90 private LinkedList<RevCommit> ret = new LinkedList<>();
91
92 MergeBaseGenerator(final RevWalk w) {
93 walker = w;
94 pending = new DateRevQueue();
95 }
96
97 void init(final AbstractRevQueue p) throws IOException {
98 try {
99 for (;;) {
100 final RevCommit c = p.next();
101 if (c == null)
102 break;
103 add(c);
104 }
105
106
107
108 recarryTest = branchMask | POPPED;
109 recarryMask = branchMask | POPPED | MERGE_BASE;
110 mergeBaseAncestor = walker.allocFlag();
111
112 for (;;) {
113 RevCommit c = _next();
114 if (c == null) {
115 break;
116 }
117 ret.add(c);
118 }
119 } finally {
120
121
122
123 walker.freeFlag(branchMask | mergeBaseAncestor);
124 }
125 }
126
127 private void add(final RevCommit c) {
128 final int flag = walker.allocFlag();
129 branchMask |= flag;
130 if ((c.flags & branchMask) != 0) {
131
132
133
134
135 throw new IllegalStateException(MessageFormat.format(JGitText.get().staleRevFlagsOn, c.name()));
136 }
137 c.flags |= flag;
138 pending.add(c);
139 }
140
141 @Override
142 int outputType() {
143 return 0;
144 }
145
146 private RevCommit _next() throws MissingObjectException,
147 IncorrectObjectTypeException, IOException {
148 for (;;) {
149 final RevCommit c = pending.next();
150 if (c == null) {
151 return null;
152 }
153
154 for (final RevCommit p : c.parents) {
155 if ((p.flags & IN_PENDING) != 0)
156 continue;
157 if ((p.flags & PARSED) == 0)
158 p.parseHeaders(walker);
159 p.flags |= IN_PENDING;
160 pending.add(p);
161 }
162
163 int carry = c.flags & branchMask;
164 boolean mb = carry == branchMask;
165 if (mb) {
166
167
168
169
170 carry |= MERGE_BASE | mergeBaseAncestor;
171 }
172 carryOntoHistory(c, carry);
173
174 if ((c.flags & MERGE_BASE) != 0) {
175
176
177
178
179
180 if (pending.everbodyHasFlag(MERGE_BASE))
181 return null;
182 continue;
183 }
184 c.flags |= POPPED;
185
186 if (mb) {
187 c.flags |= MERGE_BASE;
188 return c;
189 }
190 }
191 }
192
193 @Override
194 RevCommit next() throws MissingObjectException,
195 IncorrectObjectTypeException, IOException {
196 while (!ret.isEmpty()) {
197 RevCommit commit = ret.remove();
198 if ((commit.flags & mergeBaseAncestor) == 0) {
199 return commit;
200 }
201 }
202 return null;
203 }
204
205 private void carryOntoHistory(RevCommit c, final int carry) {
206 for (;;) {
207 final RevCommit[] pList = c.parents;
208 if (pList == null)
209 return;
210 final int n = pList.length;
211 if (n == 0)
212 return;
213
214 for (int i = 1; i < n; i++) {
215 final RevCommit p = pList[i];
216 if (!carryOntoOne(p, carry))
217 carryOntoHistory(p, carry);
218 }
219
220 c = pList[0];
221 if (carryOntoOne(c, carry))
222 break;
223 }
224 }
225
226 private boolean carryOntoOne(final RevCommit p, final int carry) {
227 final boolean haveAll = (p.flags & carry) == carry;
228 p.flags |= carry;
229
230 if ((p.flags & recarryMask) == recarryTest) {
231
232
233
234
235
236 p.flags &= ~POPPED;
237 pending.add(p);
238 carryOntoHistory(p, branchMask | MERGE_BASE);
239 return true;
240 }
241
242
243
244
245
246 return haveAll;
247 }
248 }