You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RevWalk.java 53KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695
  1. /*
  2. * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  3. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  4. * Copyright (C) 2014, Gustaf Lundh <gustaf.lundh@sonymobile.com> and others
  5. *
  6. * This program and the accompanying materials are made available under the
  7. * terms of the Eclipse Distribution License v. 1.0 which is available at
  8. * https://www.eclipse.org/org/documents/edl-v10.php.
  9. *
  10. * SPDX-License-Identifier: BSD-3-Clause
  11. */
  12. package org.eclipse.jgit.revwalk;
  13. import java.io.IOException;
  14. import java.text.MessageFormat;
  15. import java.util.ArrayList;
  16. import java.util.Collection;
  17. import java.util.EnumSet;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import org.eclipse.jgit.annotations.NonNull;
  21. import org.eclipse.jgit.annotations.Nullable;
  22. import org.eclipse.jgit.errors.CorruptObjectException;
  23. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  24. import org.eclipse.jgit.errors.LargeObjectException;
  25. import org.eclipse.jgit.errors.MissingObjectException;
  26. import org.eclipse.jgit.errors.RevWalkException;
  27. import org.eclipse.jgit.internal.JGitText;
  28. import org.eclipse.jgit.lib.AnyObjectId;
  29. import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
  30. import org.eclipse.jgit.lib.Constants;
  31. import org.eclipse.jgit.lib.MutableObjectId;
  32. import org.eclipse.jgit.lib.NullProgressMonitor;
  33. import org.eclipse.jgit.lib.ObjectId;
  34. import org.eclipse.jgit.lib.ObjectIdOwnerMap;
  35. import org.eclipse.jgit.lib.ObjectLoader;
  36. import org.eclipse.jgit.lib.ObjectReader;
  37. import org.eclipse.jgit.lib.ProgressMonitor;
  38. import org.eclipse.jgit.lib.Ref;
  39. import org.eclipse.jgit.lib.Repository;
  40. import org.eclipse.jgit.revwalk.filter.RevFilter;
  41. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  42. import org.eclipse.jgit.util.References;
  43. /**
  44. * Walks a commit graph and produces the matching commits in order.
  45. * <p>
  46. * A RevWalk instance can only be used once to generate results. Running a
  47. * second time requires creating a new RevWalk instance, or invoking
  48. * {@link #reset()} before starting again. Resetting an existing instance may be
  49. * faster for some applications as commit body parsing can be avoided on the
  50. * later invocations.
  51. * <p>
  52. * RevWalk instances are not thread-safe. Applications must either restrict
  53. * usage of a RevWalk instance to a single thread, or implement their own
  54. * synchronization at a higher level.
  55. * <p>
  56. * Multiple simultaneous RevWalk instances per
  57. * {@link org.eclipse.jgit.lib.Repository} are permitted, even from concurrent
  58. * threads. Equality of {@link org.eclipse.jgit.revwalk.RevCommit}s from two
  59. * different RevWalk instances is never true, even if their
  60. * {@link org.eclipse.jgit.lib.ObjectId}s are equal (and thus they describe the
  61. * same commit).
  62. * <p>
  63. * The offered iterator is over the list of RevCommits described by the
  64. * configuration of this instance. Applications should restrict themselves to
  65. * using either the provided Iterator or {@link #next()}, but never use both on
  66. * the same RevWalk at the same time. The Iterator may buffer RevCommits, while
  67. * {@link #next()} does not.
  68. */
  69. public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
  70. private static final int MB = 1 << 20;
  71. /**
  72. * Set on objects whose important header data has been loaded.
  73. * <p>
  74. * For a RevCommit this indicates we have pulled apart the tree and parent
  75. * references from the raw bytes available in the repository and translated
  76. * those to our own local RevTree and RevCommit instances. The raw buffer is
  77. * also available for message and other header filtering.
  78. * <p>
  79. * For a RevTag this indicates we have pulled part the tag references to
  80. * find out who the tag refers to, and what that object's type is.
  81. */
  82. static final int PARSED = 1 << 0;
  83. /**
  84. * Set on RevCommit instances added to our {@link #pending} queue.
  85. * <p>
  86. * We use this flag to avoid adding the same commit instance twice to our
  87. * queue, especially if we reached it by more than one path.
  88. */
  89. static final int SEEN = 1 << 1;
  90. /**
  91. * Set on RevCommit instances the caller does not want output.
  92. * <p>
  93. * We flag commits as uninteresting if the caller does not want commits
  94. * reachable from a commit given to {@link #markUninteresting(RevCommit)}.
  95. * This flag is always carried into the commit's parents and is a key part
  96. * of the "rev-list B --not A" feature; A is marked UNINTERESTING.
  97. */
  98. static final int UNINTERESTING = 1 << 2;
  99. /**
  100. * Set on a RevCommit that can collapse out of the history.
  101. * <p>
  102. * If the {@link #treeFilter} concluded that this commit matches his
  103. * parents' for all of the paths that the filter is interested in then we
  104. * mark the commit REWRITE. Later we can rewrite the parents of a REWRITE
  105. * child to remove chains of REWRITE commits before we produce the child to
  106. * the application.
  107. *
  108. * @see RewriteGenerator
  109. */
  110. static final int REWRITE = 1 << 3;
  111. /**
  112. * Temporary mark for use within generators or filters.
  113. * <p>
  114. * This mark is only for local use within a single scope. If someone sets
  115. * the mark they must unset it before any other code can see the mark.
  116. */
  117. static final int TEMP_MARK = 1 << 4;
  118. /**
  119. * Temporary mark for use within {@link TopoSortGenerator}.
  120. * <p>
  121. * This mark indicates the commit could not produce when it wanted to, as at
  122. * least one child was behind it. Commits with this flag are delayed until
  123. * all children have been output first.
  124. */
  125. static final int TOPO_DELAY = 1 << 5;
  126. /**
  127. * Temporary mark for use within {@link TopoNonIntermixSortGenerator}.
  128. * <p>
  129. * This mark indicates the commit has been queued for emission in
  130. * {@link TopoSortGenerator} and can be produced. This mark is removed when
  131. * the commit has been produced.
  132. */
  133. static final int TOPO_QUEUED = 1 << 6;
  134. /** Number of flag bits we keep internal for our own use. See above flags. */
  135. static final int RESERVED_FLAGS = 7;
  136. private static final int APP_FLAGS = -1 & ~((1 << RESERVED_FLAGS) - 1);
  137. final ObjectReader reader;
  138. private final boolean closeReader;
  139. final MutableObjectId idBuffer;
  140. ObjectIdOwnerMap<RevObject> objects;
  141. int freeFlags = APP_FLAGS;
  142. private int delayFreeFlags;
  143. private int retainOnReset;
  144. int carryFlags = UNINTERESTING;
  145. final ArrayList<RevCommit> roots;
  146. AbstractRevQueue queue;
  147. Generator pending;
  148. private final EnumSet<RevSort> sorting;
  149. private RevFilter filter;
  150. private TreeFilter treeFilter;
  151. private boolean retainBody = true;
  152. private boolean rewriteParents = true;
  153. private boolean firstParent;
  154. boolean shallowCommitsInitialized;
  155. private enum GetMergedIntoStrategy {
  156. RETURN_ON_FIRST_FOUND,
  157. RETURN_ON_FIRST_NOT_FOUND,
  158. EVALUATE_ALL
  159. }
  160. /**
  161. * Create a new revision walker for a given repository.
  162. *
  163. * @param repo
  164. * the repository the walker will obtain data from. An
  165. * ObjectReader will be created by the walker, and will be closed
  166. * when the walker is closed.
  167. */
  168. public RevWalk(Repository repo) {
  169. this(repo.newObjectReader(), true);
  170. }
  171. /**
  172. * Create a new revision walker for a given repository.
  173. * <p>
  174. *
  175. * @param or
  176. * the reader the walker will obtain data from. The reader is not
  177. * closed when the walker is closed (but is closed by {@link
  178. * #dispose()}.
  179. */
  180. public RevWalk(ObjectReader or) {
  181. this(or, false);
  182. }
  183. private RevWalk(ObjectReader or, boolean closeReader) {
  184. reader = or;
  185. idBuffer = new MutableObjectId();
  186. objects = new ObjectIdOwnerMap<>();
  187. roots = new ArrayList<>();
  188. queue = new DateRevQueue(false);
  189. pending = new StartGenerator(this);
  190. sorting = EnumSet.of(RevSort.NONE);
  191. filter = RevFilter.ALL;
  192. treeFilter = TreeFilter.ALL;
  193. this.closeReader = closeReader;
  194. }
  195. /**
  196. * Get the reader this walker is using to load objects.
  197. *
  198. * @return the reader this walker is using to load objects.
  199. */
  200. public ObjectReader getObjectReader() {
  201. return reader;
  202. }
  203. /**
  204. * Get a reachability checker for commits over this revwalk.
  205. *
  206. * @return the most efficient reachability checker for this repository.
  207. * @throws IOException
  208. * if it cannot open any of the underlying indices.
  209. *
  210. * @since 5.4
  211. * @deprecated use {@code ObjectReader#createReachabilityChecker(RevWalk)}
  212. * instead.
  213. */
  214. @Deprecated
  215. public final ReachabilityChecker createReachabilityChecker()
  216. throws IOException {
  217. return reader.createReachabilityChecker(this);
  218. }
  219. /**
  220. * {@inheritDoc}
  221. * <p>
  222. * Release any resources used by this walker's reader.
  223. * <p>
  224. * A walker that has been released can be used again, but may need to be
  225. * released after the subsequent usage.
  226. *
  227. * @since 4.0
  228. */
  229. @Override
  230. public void close() {
  231. if (closeReader) {
  232. reader.close();
  233. }
  234. }
  235. /**
  236. * Mark a commit to start graph traversal from.
  237. * <p>
  238. * Callers are encouraged to use {@link #parseCommit(AnyObjectId)} to obtain
  239. * the commit reference, rather than {@link #lookupCommit(AnyObjectId)}, as
  240. * this method requires the commit to be parsed before it can be added as a
  241. * root for the traversal.
  242. * <p>
  243. * The method will automatically parse an unparsed commit, but error
  244. * handling may be more difficult for the application to explain why a
  245. * RevCommit is not actually a commit. The object pool of this walker would
  246. * also be 'poisoned' by the non-commit RevCommit.
  247. *
  248. * @param c
  249. * the commit to start traversing from. The commit passed must be
  250. * from this same revision walker.
  251. * @throws org.eclipse.jgit.errors.MissingObjectException
  252. * the commit supplied is not available from the object
  253. * database. This usually indicates the supplied commit is
  254. * invalid, but the reference was constructed during an earlier
  255. * invocation to {@link #lookupCommit(AnyObjectId)}.
  256. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  257. * the object was not parsed yet and it was discovered during
  258. * parsing that it is not actually a commit. This usually
  259. * indicates the caller supplied a non-commit SHA-1 to
  260. * {@link #lookupCommit(AnyObjectId)}.
  261. * @throws java.io.IOException
  262. * a pack file or loose object could not be read.
  263. */
  264. public void markStart(RevCommit c) throws MissingObjectException,
  265. IncorrectObjectTypeException, IOException {
  266. if ((c.flags & SEEN) != 0)
  267. return;
  268. if ((c.flags & PARSED) == 0)
  269. c.parseHeaders(this);
  270. c.flags |= SEEN;
  271. roots.add(c);
  272. queue.add(c);
  273. }
  274. /**
  275. * Mark commits to start graph traversal from.
  276. *
  277. * @param list
  278. * commits to start traversing from. The commits passed must be
  279. * from this same revision walker.
  280. * @throws org.eclipse.jgit.errors.MissingObjectException
  281. * one of the commits supplied is not available from the object
  282. * database. This usually indicates the supplied commit is
  283. * invalid, but the reference was constructed during an earlier
  284. * invocation to {@link #lookupCommit(AnyObjectId)}.
  285. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  286. * the object was not parsed yet and it was discovered during
  287. * parsing that it is not actually a commit. This usually
  288. * indicates the caller supplied a non-commit SHA-1 to
  289. * {@link #lookupCommit(AnyObjectId)}.
  290. * @throws java.io.IOException
  291. * a pack file or loose object could not be read.
  292. */
  293. public void markStart(Collection<RevCommit> list)
  294. throws MissingObjectException, IncorrectObjectTypeException,
  295. IOException {
  296. for (RevCommit c : list)
  297. markStart(c);
  298. }
  299. /**
  300. * Mark a commit to not produce in the output.
  301. * <p>
  302. * Uninteresting commits denote not just themselves but also their entire
  303. * ancestry chain, back until the merge base of an uninteresting commit and
  304. * an otherwise interesting commit.
  305. * <p>
  306. * Callers are encouraged to use {@link #parseCommit(AnyObjectId)} to obtain
  307. * the commit reference, rather than {@link #lookupCommit(AnyObjectId)}, as
  308. * this method requires the commit to be parsed before it can be added as a
  309. * root for the traversal.
  310. * <p>
  311. * The method will automatically parse an unparsed commit, but error
  312. * handling may be more difficult for the application to explain why a
  313. * RevCommit is not actually a commit. The object pool of this walker would
  314. * also be 'poisoned' by the non-commit RevCommit.
  315. *
  316. * @param c
  317. * the commit to start traversing from. The commit passed must be
  318. * from this same revision walker.
  319. * @throws org.eclipse.jgit.errors.MissingObjectException
  320. * the commit supplied is not available from the object
  321. * database. This usually indicates the supplied commit is
  322. * invalid, but the reference was constructed during an earlier
  323. * invocation to {@link #lookupCommit(AnyObjectId)}.
  324. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  325. * the object was not parsed yet and it was discovered during
  326. * parsing that it is not actually a commit. This usually
  327. * indicates the caller supplied a non-commit SHA-1 to
  328. * {@link #lookupCommit(AnyObjectId)}.
  329. * @throws java.io.IOException
  330. * a pack file or loose object could not be read.
  331. */
  332. public void markUninteresting(RevCommit c)
  333. throws MissingObjectException, IncorrectObjectTypeException,
  334. IOException {
  335. c.flags |= UNINTERESTING;
  336. carryFlagsImpl(c);
  337. markStart(c);
  338. }
  339. /**
  340. * Determine if a commit is reachable from another commit.
  341. * <p>
  342. * A commit <code>base</code> is an ancestor of <code>tip</code> if we
  343. * can find a path of commits that leads from <code>tip</code> and ends at
  344. * <code>base</code>.
  345. * <p>
  346. * This utility function resets the walker, inserts the two supplied
  347. * commits, and then executes a walk until an answer can be obtained.
  348. * Currently allocated RevFlags that have been added to RevCommit instances
  349. * will be retained through the reset.
  350. *
  351. * @param base
  352. * commit the caller thinks is reachable from <code>tip</code>.
  353. * @param tip
  354. * commit to start iteration from, and which is most likely a
  355. * descendant (child) of <code>base</code>.
  356. * @return true if there is a path directly from <code>tip</code> to
  357. * <code>base</code> (and thus <code>base</code> is fully merged
  358. * into <code>tip</code>); false otherwise.
  359. * @throws org.eclipse.jgit.errors.MissingObjectException
  360. * one or more of the next commit's parents are not available
  361. * from the object database, but were thought to be candidates
  362. * for traversal. This usually indicates a broken link.
  363. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  364. * one or more of the next commit's parents are not actually
  365. * commit objects.
  366. * @throws java.io.IOException
  367. * a pack file or loose object could not be read.
  368. */
  369. public boolean isMergedInto(RevCommit base, RevCommit tip)
  370. throws MissingObjectException, IncorrectObjectTypeException,
  371. IOException {
  372. final RevFilter oldRF = filter;
  373. final TreeFilter oldTF = treeFilter;
  374. try {
  375. finishDelayedFreeFlags();
  376. reset(~freeFlags & APP_FLAGS);
  377. filter = RevFilter.MERGE_BASE;
  378. treeFilter = TreeFilter.ALL;
  379. markStart(tip);
  380. markStart(base);
  381. RevCommit mergeBase;
  382. while ((mergeBase = next()) != null) {
  383. if (References.isSameObject(mergeBase, base)) {
  384. return true;
  385. }
  386. }
  387. return false;
  388. } finally {
  389. filter = oldRF;
  390. treeFilter = oldTF;
  391. }
  392. }
  393. /**
  394. * Determine the Refs into which a commit is merged.
  395. * <p>
  396. * A commit is merged into a ref if we can find a path of commits that leads
  397. * from that specific ref and ends at <code>commit</code>.
  398. * <p>
  399. *
  400. * @param commit
  401. * commit the caller thinks is reachable from <code>refs</code>.
  402. * @param refs
  403. * refs to start iteration from, and which is most likely a
  404. * descendant (child) of <code>commit</code>.
  405. * @return list of refs that are reachable from <code>commit</code>.
  406. * @throws java.io.IOException
  407. * a pack file or loose object could not be read.
  408. * @since 5.12
  409. */
  410. public List<Ref> getMergedInto(RevCommit commit, Collection<Ref> refs)
  411. throws IOException{
  412. return getMergedInto(commit, refs, NullProgressMonitor.INSTANCE);
  413. }
  414. /**
  415. * Determine the Refs into which a commit is merged.
  416. * <p>
  417. * A commit is merged into a ref if we can find a path of commits that leads
  418. * from that specific ref and ends at <code>commit</code>.
  419. * <p>
  420. *
  421. * @param commit
  422. * commit the caller thinks is reachable from <code>refs</code>.
  423. * @param refs
  424. * refs to start iteration from, and which is most likely a
  425. * descendant (child) of <code>commit</code>.
  426. * @param monitor
  427. * the callback for progress and cancellation
  428. * @return list of refs that are reachable from <code>commit</code>.
  429. * @throws java.io.IOException
  430. * a pack file or loose object could not be read.
  431. * @since 5.12
  432. */
  433. public List<Ref> getMergedInto(RevCommit commit, Collection<Ref> refs,
  434. ProgressMonitor monitor) throws IOException{
  435. return getMergedInto(commit, refs,
  436. GetMergedIntoStrategy.EVALUATE_ALL,
  437. monitor);
  438. }
  439. /**
  440. * Determine if a <code>commit</code> is merged into any of the given
  441. * <code>refs</code>.
  442. *
  443. * @param commit
  444. * commit the caller thinks is reachable from <code>refs</code>.
  445. * @param refs
  446. * refs to start iteration from, and which is most likely a
  447. * descendant (child) of <code>commit</code>.
  448. * @return true if commit is merged into any of the refs; false otherwise.
  449. * @throws java.io.IOException
  450. * a pack file or loose object could not be read.
  451. * @since 5.12
  452. */
  453. public boolean isMergedIntoAny(RevCommit commit, Collection<Ref> refs)
  454. throws IOException {
  455. return getMergedInto(commit, refs,
  456. GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND,
  457. NullProgressMonitor.INSTANCE).size() > 0;
  458. }
  459. /**
  460. * Determine if a <code>commit</code> is merged into all of the given
  461. * <code>refs</code>.
  462. *
  463. * @param commit
  464. * commit the caller thinks is reachable from <code>refs</code>.
  465. * @param refs
  466. * refs to start iteration from, and which is most likely a
  467. * descendant (child) of <code>commit</code>.
  468. * @return true if commit is merged into all of the refs; false otherwise.
  469. * @throws java.io.IOException
  470. * a pack file or loose object could not be read.
  471. * @since 5.12
  472. */
  473. public boolean isMergedIntoAll(RevCommit commit, Collection<Ref> refs)
  474. throws IOException {
  475. return getMergedInto(commit, refs,
  476. GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND,
  477. NullProgressMonitor.INSTANCE).size()
  478. == refs.size();
  479. }
  480. private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks,
  481. Enum returnStrategy, ProgressMonitor monitor) throws IOException {
  482. List<Ref> result = new ArrayList<>();
  483. RevFilter oldRF = filter;
  484. TreeFilter oldTF = treeFilter;
  485. try {
  486. finishDelayedFreeFlags();
  487. filter = RevFilter.ALL;
  488. treeFilter = TreeFilter.ALL;
  489. for (Ref r: haystacks) {
  490. if (monitor.isCancelled()) {
  491. return result;
  492. }
  493. monitor.update(1);
  494. RevObject o = parseAny(r.getObjectId());
  495. if (!(o instanceof RevCommit)) {
  496. continue;
  497. }
  498. RevCommit c = (RevCommit) o;
  499. resetRetain(RevFlag.UNINTERESTING);
  500. markStart(c);
  501. boolean commitFound = false;
  502. RevCommit next;
  503. while ((next = next()) != null) {
  504. if (References.isSameObject(next, needle)) {
  505. result.add(r);
  506. if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND) {
  507. return result;
  508. }
  509. commitFound = true;
  510. break;
  511. }
  512. }
  513. if(!commitFound){
  514. markUninteresting(c);
  515. if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND) {
  516. return result;
  517. }
  518. }
  519. }
  520. } finally {
  521. reset(~freeFlags & APP_FLAGS);
  522. filter = oldRF;
  523. treeFilter = oldTF;
  524. }
  525. return result;
  526. }
  527. /**
  528. * Pop the next most recent commit.
  529. *
  530. * @return next most recent commit; null if traversal is over.
  531. * @throws org.eclipse.jgit.errors.MissingObjectException
  532. * one or more of the next commit's parents are not available
  533. * from the object database, but were thought to be candidates
  534. * for traversal. This usually indicates a broken link.
  535. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  536. * one or more of the next commit's parents are not actually
  537. * commit objects.
  538. * @throws java.io.IOException
  539. * a pack file or loose object could not be read.
  540. */
  541. public RevCommit next() throws MissingObjectException,
  542. IncorrectObjectTypeException, IOException {
  543. return pending.next();
  544. }
  545. /**
  546. * Obtain the sort types applied to the commits returned.
  547. *
  548. * @return the sorting strategies employed. At least one strategy is always
  549. * used, but that strategy may be
  550. * {@link org.eclipse.jgit.revwalk.RevSort#NONE}.
  551. */
  552. public EnumSet<RevSort> getRevSort() {
  553. return sorting.clone();
  554. }
  555. /**
  556. * Check whether the provided sorting strategy is enabled.
  557. *
  558. * @param sort
  559. * a sorting strategy to look for.
  560. * @return true if this strategy is enabled, false otherwise
  561. */
  562. public boolean hasRevSort(RevSort sort) {
  563. return sorting.contains(sort);
  564. }
  565. /**
  566. * Select a single sorting strategy for the returned commits.
  567. * <p>
  568. * Disables all sorting strategies, then enables only the single strategy
  569. * supplied by the caller.
  570. *
  571. * @param s
  572. * a sorting strategy to enable.
  573. */
  574. public void sort(RevSort s) {
  575. assertNotStarted();
  576. sorting.clear();
  577. sorting.add(s);
  578. }
  579. /**
  580. * Add or remove a sorting strategy for the returned commits.
  581. * <p>
  582. * Multiple strategies can be applied at once, in which case some strategies
  583. * may take precedence over others. As an example,
  584. * {@link org.eclipse.jgit.revwalk.RevSort#TOPO} must take precedence over
  585. * {@link org.eclipse.jgit.revwalk.RevSort#COMMIT_TIME_DESC}, otherwise it
  586. * cannot enforce its ordering.
  587. *
  588. * @param s
  589. * a sorting strategy to enable or disable.
  590. * @param use
  591. * true if this strategy should be used, false if it should be
  592. * removed.
  593. */
  594. public void sort(RevSort s, boolean use) {
  595. assertNotStarted();
  596. if (use)
  597. sorting.add(s);
  598. else
  599. sorting.remove(s);
  600. if (sorting.size() > 1)
  601. sorting.remove(RevSort.NONE);
  602. else if (sorting.isEmpty())
  603. sorting.add(RevSort.NONE);
  604. }
  605. /**
  606. * Get the currently configured commit filter.
  607. *
  608. * @return the current filter. Never null as a filter is always needed.
  609. */
  610. @NonNull
  611. public RevFilter getRevFilter() {
  612. return filter;
  613. }
  614. /**
  615. * Set the commit filter for this walker.
  616. * <p>
  617. * Multiple filters may be combined by constructing an arbitrary tree of
  618. * <code>AndRevFilter</code> or <code>OrRevFilter</code> instances to
  619. * describe the boolean expression required by the application. Custom
  620. * filter implementations may also be constructed by applications.
  621. * <p>
  622. * Note that filters are not thread-safe and may not be shared by concurrent
  623. * RevWalk instances. Every RevWalk must be supplied its own unique filter,
  624. * unless the filter implementation specifically states it is (and always
  625. * will be) thread-safe. Callers may use
  626. * {@link org.eclipse.jgit.revwalk.filter.RevFilter#clone()} to create a
  627. * unique filter tree for this RevWalk instance.
  628. *
  629. * @param newFilter
  630. * the new filter. If null the special
  631. * {@link org.eclipse.jgit.revwalk.filter.RevFilter#ALL} filter
  632. * will be used instead, as it matches every commit.
  633. * @see org.eclipse.jgit.revwalk.filter.AndRevFilter
  634. * @see org.eclipse.jgit.revwalk.filter.OrRevFilter
  635. */
  636. public void setRevFilter(RevFilter newFilter) {
  637. assertNotStarted();
  638. filter = newFilter != null ? newFilter : RevFilter.ALL;
  639. }
  640. /**
  641. * Get the tree filter used to simplify commits by modified paths.
  642. *
  643. * @return the current filter. Never null as a filter is always needed. If
  644. * no filter is being applied
  645. * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} is
  646. * returned.
  647. */
  648. @NonNull
  649. public TreeFilter getTreeFilter() {
  650. return treeFilter;
  651. }
  652. /**
  653. * Set the tree filter used to simplify commits by modified paths.
  654. * <p>
  655. * If null or {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} the
  656. * path limiter is removed. Commits will not be simplified.
  657. * <p>
  658. * If non-null and not
  659. * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} then the tree
  660. * filter will be installed. Commits will have their ancestry simplified to
  661. * hide commits that do not contain tree entries matched by the filter,
  662. * unless {@code setRewriteParents(false)} is called.
  663. * <p>
  664. * Usually callers should be inserting a filter graph including
  665. * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF} along with
  666. * one or more {@link org.eclipse.jgit.treewalk.filter.PathFilter}
  667. * instances.
  668. *
  669. * @param newFilter
  670. * new filter. If null the special
  671. * {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL} filter
  672. * will be used instead, as it matches everything.
  673. * @see org.eclipse.jgit.treewalk.filter.PathFilter
  674. */
  675. public void setTreeFilter(TreeFilter newFilter) {
  676. assertNotStarted();
  677. treeFilter = newFilter != null ? newFilter : TreeFilter.ALL;
  678. }
  679. /**
  680. * Set whether to rewrite parent pointers when filtering by modified paths.
  681. * <p>
  682. * By default, when {@link #setTreeFilter(TreeFilter)} is called with non-
  683. * null and non-{@link org.eclipse.jgit.treewalk.filter.TreeFilter#ALL}
  684. * filter, commits will have their ancestry simplified and parents rewritten
  685. * to hide commits that do not match the filter.
  686. * <p>
  687. * This behavior can be bypassed by passing false to this method.
  688. *
  689. * @param rewrite
  690. * whether to rewrite parents; defaults to true.
  691. * @since 3.4
  692. */
  693. public void setRewriteParents(boolean rewrite) {
  694. rewriteParents = rewrite;
  695. }
  696. boolean getRewriteParents() {
  697. return rewriteParents;
  698. }
  699. /**
  700. * Should the body of a commit or tag be retained after parsing its headers?
  701. * <p>
  702. * Usually the body is always retained, but some application code might not
  703. * care and would prefer to discard the body of a commit as early as
  704. * possible, to reduce memory usage.
  705. * <p>
  706. * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
  707. * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
  708. *
  709. * @return true if the body should be retained; false it is discarded.
  710. */
  711. public boolean isRetainBody() {
  712. return retainBody;
  713. }
  714. /**
  715. * Set whether or not the body of a commit or tag is retained.
  716. * <p>
  717. * If a body of a commit or tag is not retained, the application must call
  718. * {@link #parseBody(RevObject)} before the body can be safely accessed
  719. * through the type specific access methods.
  720. * <p>
  721. * True by default on {@link org.eclipse.jgit.revwalk.RevWalk} and false by
  722. * default for {@link org.eclipse.jgit.revwalk.ObjectWalk}.
  723. *
  724. * @param retain
  725. * true to retain bodies; false to discard them early.
  726. */
  727. public void setRetainBody(boolean retain) {
  728. retainBody = retain;
  729. }
  730. /**
  731. * @return whether only first-parent links should be followed when walking.
  732. *
  733. * @since 5.5
  734. */
  735. public boolean isFirstParent() {
  736. return firstParent;
  737. }
  738. /**
  739. * Set whether or not only first parent links should be followed.
  740. * <p>
  741. * If set, second- and higher-parent links are not traversed at all.
  742. * <p>
  743. * This must be called prior to {@link #markStart(RevCommit)}.
  744. *
  745. * @param enable
  746. * true to walk only first-parent links.
  747. *
  748. * @since 5.5
  749. */
  750. public void setFirstParent(boolean enable) {
  751. assertNotStarted();
  752. assertNoCommitsMarkedStart();
  753. firstParent = enable;
  754. queue = new DateRevQueue(firstParent);
  755. pending = new StartGenerator(this);
  756. }
  757. /**
  758. * Locate a reference to a blob without loading it.
  759. * <p>
  760. * The blob may or may not exist in the repository. It is impossible to tell
  761. * from this method's return value.
  762. *
  763. * @param id
  764. * name of the blob object.
  765. * @return reference to the blob object. Never null.
  766. */
  767. @NonNull
  768. public RevBlob lookupBlob(AnyObjectId id) {
  769. RevBlob c = (RevBlob) objects.get(id);
  770. if (c == null) {
  771. c = new RevBlob(id);
  772. objects.add(c);
  773. }
  774. return c;
  775. }
  776. /**
  777. * Locate a reference to a tree without loading it.
  778. * <p>
  779. * The tree may or may not exist in the repository. It is impossible to tell
  780. * from this method's return value.
  781. *
  782. * @param id
  783. * name of the tree object.
  784. * @return reference to the tree object. Never null.
  785. */
  786. @NonNull
  787. public RevTree lookupTree(AnyObjectId id) {
  788. RevTree c = (RevTree) objects.get(id);
  789. if (c == null) {
  790. c = new RevTree(id);
  791. objects.add(c);
  792. }
  793. return c;
  794. }
  795. /**
  796. * Locate a reference to a commit without loading it.
  797. * <p>
  798. * The commit may or may not exist in the repository. It is impossible to
  799. * tell from this method's return value.
  800. * <p>
  801. * See {@link #parseHeaders(RevObject)} and {@link #parseBody(RevObject)}
  802. * for loading contents.
  803. *
  804. * @param id
  805. * name of the commit object.
  806. * @return reference to the commit object. Never null.
  807. */
  808. @NonNull
  809. public RevCommit lookupCommit(AnyObjectId id) {
  810. RevCommit c = (RevCommit) objects.get(id);
  811. if (c == null) {
  812. c = createCommit(id);
  813. objects.add(c);
  814. }
  815. return c;
  816. }
  817. /**
  818. * Locate a reference to a tag without loading it.
  819. * <p>
  820. * The tag may or may not exist in the repository. It is impossible to tell
  821. * from this method's return value.
  822. *
  823. * @param id
  824. * name of the tag object.
  825. * @return reference to the tag object. Never null.
  826. */
  827. @NonNull
  828. public RevTag lookupTag(AnyObjectId id) {
  829. RevTag c = (RevTag) objects.get(id);
  830. if (c == null) {
  831. c = new RevTag(id);
  832. objects.add(c);
  833. }
  834. return c;
  835. }
  836. /**
  837. * Locate a reference to any object without loading it.
  838. * <p>
  839. * The object may or may not exist in the repository. It is impossible to
  840. * tell from this method's return value.
  841. *
  842. * @param id
  843. * name of the object.
  844. * @param type
  845. * type of the object. Must be a valid Git object type.
  846. * @return reference to the object. Never null.
  847. */
  848. @NonNull
  849. public RevObject lookupAny(AnyObjectId id, int type) {
  850. RevObject r = objects.get(id);
  851. if (r == null) {
  852. switch (type) {
  853. case Constants.OBJ_COMMIT:
  854. r = createCommit(id);
  855. break;
  856. case Constants.OBJ_TREE:
  857. r = new RevTree(id);
  858. break;
  859. case Constants.OBJ_BLOB:
  860. r = new RevBlob(id);
  861. break;
  862. case Constants.OBJ_TAG:
  863. r = new RevTag(id);
  864. break;
  865. default:
  866. throw new IllegalArgumentException(MessageFormat.format(
  867. JGitText.get().invalidGitType, Integer.valueOf(type)));
  868. }
  869. objects.add(r);
  870. }
  871. return r;
  872. }
  873. /**
  874. * Locate an object that was previously allocated in this walk.
  875. *
  876. * @param id
  877. * name of the object.
  878. * @return reference to the object if it has been previously located;
  879. * otherwise null.
  880. */
  881. public RevObject lookupOrNull(AnyObjectId id) {
  882. return objects.get(id);
  883. }
  884. /**
  885. * Locate a reference to a commit and immediately parse its content.
  886. * <p>
  887. * Unlike {@link #lookupCommit(AnyObjectId)} this method only returns
  888. * successfully if the commit object exists, is verified to be a commit, and
  889. * was parsed without error.
  890. *
  891. * @param id
  892. * name of the commit object.
  893. * @return reference to the commit object. Never null.
  894. * @throws org.eclipse.jgit.errors.MissingObjectException
  895. * the supplied commit does not exist.
  896. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  897. * the supplied id is not a commit or an annotated tag.
  898. * @throws java.io.IOException
  899. * a pack file or loose object could not be read.
  900. */
  901. @NonNull
  902. public RevCommit parseCommit(AnyObjectId id)
  903. throws MissingObjectException, IncorrectObjectTypeException,
  904. IOException {
  905. RevObject c = peel(parseAny(id));
  906. if (!(c instanceof RevCommit))
  907. throw new IncorrectObjectTypeException(id.toObjectId(),
  908. Constants.TYPE_COMMIT);
  909. return (RevCommit) c;
  910. }
  911. /**
  912. * Locate a reference to a tree.
  913. * <p>
  914. * This method only returns successfully if the tree object exists, is
  915. * verified to be a tree.
  916. *
  917. * @param id
  918. * name of the tree object, or a commit or annotated tag that may
  919. * reference a tree.
  920. * @return reference to the tree object. Never null.
  921. * @throws org.eclipse.jgit.errors.MissingObjectException
  922. * the supplied tree does not exist.
  923. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  924. * the supplied id is not a tree, a commit or an annotated tag.
  925. * @throws java.io.IOException
  926. * a pack file or loose object could not be read.
  927. */
  928. @NonNull
  929. public RevTree parseTree(AnyObjectId id)
  930. throws MissingObjectException, IncorrectObjectTypeException,
  931. IOException {
  932. RevObject c = peel(parseAny(id));
  933. final RevTree t;
  934. if (c instanceof RevCommit)
  935. t = ((RevCommit) c).getTree();
  936. else if (!(c instanceof RevTree))
  937. throw new IncorrectObjectTypeException(id.toObjectId(),
  938. Constants.TYPE_TREE);
  939. else
  940. t = (RevTree) c;
  941. parseHeaders(t);
  942. return t;
  943. }
  944. /**
  945. * Locate a reference to an annotated tag and immediately parse its content.
  946. * <p>
  947. * Unlike {@link #lookupTag(AnyObjectId)} this method only returns
  948. * successfully if the tag object exists, is verified to be a tag, and was
  949. * parsed without error.
  950. *
  951. * @param id
  952. * name of the tag object.
  953. * @return reference to the tag object. Never null.
  954. * @throws org.eclipse.jgit.errors.MissingObjectException
  955. * the supplied tag does not exist.
  956. * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  957. * the supplied id is not a tag or an annotated tag.
  958. * @throws java.io.IOException
  959. * a pack file or loose object could not be read.
  960. */
  961. @NonNull
  962. public RevTag parseTag(AnyObjectId id) throws MissingObjectException,
  963. IncorrectObjectTypeException, IOException {
  964. RevObject c = parseAny(id);
  965. if (!(c instanceof RevTag))
  966. throw new IncorrectObjectTypeException(id.toObjectId(),
  967. Constants.TYPE_TAG);
  968. return (RevTag) c;
  969. }
  970. /**
  971. * Locate a reference to any object and immediately parse its headers.
  972. * <p>
  973. * This method only returns successfully if the object exists and was parsed
  974. * without error. Parsing an object can be expensive as the type must be
  975. * determined. For blobs this may mean the blob content was unpacked
  976. * unnecessarily, and thrown away.
  977. *
  978. * @param id
  979. * name of the object.
  980. * @return reference to the object. Never null.
  981. * @throws org.eclipse.jgit.errors.MissingObjectException
  982. * the supplied does not exist.
  983. * @throws java.io.IOException
  984. * a pack file or loose object could not be read.
  985. */
  986. @NonNull
  987. public RevObject parseAny(AnyObjectId id)
  988. throws MissingObjectException, IOException {
  989. RevObject r = objects.get(id);
  990. if (r == null)
  991. r = parseNew(id, reader.open(id));
  992. else
  993. parseHeaders(r);
  994. return r;
  995. }
  996. private RevObject parseNew(AnyObjectId id, ObjectLoader ldr)
  997. throws LargeObjectException, CorruptObjectException,
  998. MissingObjectException, IOException {
  999. RevObject r;
  1000. int type = ldr.getType();
  1001. switch (type) {
  1002. case Constants.OBJ_COMMIT: {
  1003. final RevCommit c = createCommit(id);
  1004. c.parseCanonical(this, getCachedBytes(c, ldr));
  1005. r = c;
  1006. break;
  1007. }
  1008. case Constants.OBJ_TREE: {
  1009. r = new RevTree(id);
  1010. r.flags |= PARSED;
  1011. break;
  1012. }
  1013. case Constants.OBJ_BLOB: {
  1014. r = new RevBlob(id);
  1015. r.flags |= PARSED;
  1016. break;
  1017. }
  1018. case Constants.OBJ_TAG: {
  1019. final RevTag t = new RevTag(id);
  1020. t.parseCanonical(this, getCachedBytes(t, ldr));
  1021. r = t;
  1022. break;
  1023. }
  1024. default:
  1025. throw new IllegalArgumentException(MessageFormat.format(
  1026. JGitText.get().badObjectType, Integer.valueOf(type)));
  1027. }
  1028. objects.add(r);
  1029. return r;
  1030. }
  1031. byte[] getCachedBytes(RevObject obj) throws LargeObjectException,
  1032. MissingObjectException, IncorrectObjectTypeException, IOException {
  1033. return getCachedBytes(obj, reader.open(obj, obj.getType()));
  1034. }
  1035. byte[] getCachedBytes(RevObject obj, ObjectLoader ldr)
  1036. throws LargeObjectException, MissingObjectException, IOException {
  1037. try {
  1038. return ldr.getCachedBytes(5 * MB);
  1039. } catch (LargeObjectException tooBig) {
  1040. tooBig.setObjectId(obj);
  1041. throw tooBig;
  1042. }
  1043. }
  1044. /**
  1045. * Asynchronous object parsing.
  1046. *
  1047. * @param objectIds
  1048. * objects to open from the object store. The supplied collection
  1049. * must not be modified until the queue has finished.
  1050. * @param reportMissing
  1051. * if true missing objects are reported by calling failure with a
  1052. * MissingObjectException. This may be more expensive for the
  1053. * implementation to guarantee. If false the implementation may
  1054. * choose to report MissingObjectException, or silently skip over
  1055. * the object with no warning.
  1056. * @return queue to read the objects from.
  1057. */
  1058. public <T extends ObjectId> AsyncRevObjectQueue parseAny(
  1059. Iterable<T> objectIds, boolean reportMissing) {
  1060. List<T> need = new ArrayList<>();
  1061. List<RevObject> have = new ArrayList<>();
  1062. for (T id : objectIds) {
  1063. RevObject r = objects.get(id);
  1064. if (r != null && (r.flags & PARSED) != 0)
  1065. have.add(r);
  1066. else
  1067. need.add(id);
  1068. }
  1069. final Iterator<RevObject> objItr = have.iterator();
  1070. if (need.isEmpty()) {
  1071. return new AsyncRevObjectQueue() {
  1072. @Override
  1073. public RevObject next() {
  1074. return objItr.hasNext() ? objItr.next() : null;
  1075. }
  1076. @Override
  1077. public boolean cancel(boolean mayInterruptIfRunning) {
  1078. return true;
  1079. }
  1080. @Override
  1081. public void release() {
  1082. // In-memory only, no action required.
  1083. }
  1084. };
  1085. }
  1086. final AsyncObjectLoaderQueue<T> lItr = reader.open(need, reportMissing);
  1087. return new AsyncRevObjectQueue() {
  1088. @Override
  1089. public RevObject next() throws MissingObjectException,
  1090. IncorrectObjectTypeException, IOException {
  1091. if (objItr.hasNext())
  1092. return objItr.next();
  1093. if (!lItr.next())
  1094. return null;
  1095. ObjectId id = lItr.getObjectId();
  1096. ObjectLoader ldr = lItr.open();
  1097. RevObject r = objects.get(id);
  1098. if (r == null)
  1099. r = parseNew(id, ldr);
  1100. else if (r instanceof RevCommit) {
  1101. byte[] raw = ldr.getCachedBytes();
  1102. ((RevCommit) r).parseCanonical(RevWalk.this, raw);
  1103. } else if (r instanceof RevTag) {
  1104. byte[] raw = ldr.getCachedBytes();
  1105. ((RevTag) r).parseCanonical(RevWalk.this, raw);
  1106. } else
  1107. r.flags |= PARSED;
  1108. return r;
  1109. }
  1110. @Override
  1111. public boolean cancel(boolean mayInterruptIfRunning) {
  1112. return lItr.cancel(mayInterruptIfRunning);
  1113. }
  1114. @Override
  1115. public void release() {
  1116. lItr.release();
  1117. }
  1118. };
  1119. }
  1120. /**
  1121. * Ensure the object's critical headers have been parsed.
  1122. * <p>
  1123. * This method only returns successfully if the object exists and was parsed
  1124. * without error.
  1125. *
  1126. * @param obj
  1127. * the object the caller needs to be parsed.
  1128. * @throws org.eclipse.jgit.errors.MissingObjectException
  1129. * the supplied does not exist.
  1130. * @throws java.io.IOException
  1131. * a pack file or loose object could not be read.
  1132. */
  1133. public void parseHeaders(RevObject obj)
  1134. throws MissingObjectException, IOException {
  1135. if ((obj.flags & PARSED) == 0)
  1136. obj.parseHeaders(this);
  1137. }
  1138. /**
  1139. * Ensure the object's full body content is available.
  1140. * <p>
  1141. * This method only returns successfully if the object exists and was parsed
  1142. * without error.
  1143. *
  1144. * @param obj
  1145. * the object the caller needs to be parsed.
  1146. * @throws org.eclipse.jgit.errors.MissingObjectException
  1147. * the supplied does not exist.
  1148. * @throws java.io.IOException
  1149. * a pack file or loose object could not be read.
  1150. */
  1151. public void parseBody(RevObject obj)
  1152. throws MissingObjectException, IOException {
  1153. obj.parseBody(this);
  1154. }
  1155. /**
  1156. * Peel back annotated tags until a non-tag object is found.
  1157. *
  1158. * @param obj
  1159. * the starting object.
  1160. * @return If {@code obj} is not an annotated tag, {@code obj}. Otherwise
  1161. * the first non-tag object that {@code obj} references. The
  1162. * returned object's headers have been parsed.
  1163. * @throws org.eclipse.jgit.errors.MissingObjectException
  1164. * a referenced object cannot be found.
  1165. * @throws java.io.IOException
  1166. * a pack file or loose object could not be read.
  1167. */
  1168. public RevObject peel(RevObject obj) throws MissingObjectException,
  1169. IOException {
  1170. while (obj instanceof RevTag) {
  1171. parseHeaders(obj);
  1172. obj = ((RevTag) obj).getObject();
  1173. }
  1174. parseHeaders(obj);
  1175. return obj;
  1176. }
  1177. /**
  1178. * Create a new flag for application use during walking.
  1179. * <p>
  1180. * Applications are only assured to be able to create 24 unique flags on any
  1181. * given revision walker instance. Any flags beyond 24 are offered only if
  1182. * the implementation has extra free space within its internal storage.
  1183. *
  1184. * @param name
  1185. * description of the flag, primarily useful for debugging.
  1186. * @return newly constructed flag instance.
  1187. * @throws java.lang.IllegalArgumentException
  1188. * too many flags have been reserved on this revision walker.
  1189. */
  1190. public RevFlag newFlag(String name) {
  1191. final int m = allocFlag();
  1192. return new RevFlag(this, name, m);
  1193. }
  1194. int allocFlag() {
  1195. if (freeFlags == 0)
  1196. throw new IllegalArgumentException(MessageFormat.format(
  1197. JGitText.get().flagsAlreadyCreated,
  1198. Integer.valueOf(32 - RESERVED_FLAGS)));
  1199. final int m = Integer.lowestOneBit(freeFlags);
  1200. freeFlags &= ~m;
  1201. return m;
  1202. }
  1203. /**
  1204. * Automatically carry a flag from a child commit to its parents.
  1205. * <p>
  1206. * A carried flag is copied from the child commit onto its parents when the
  1207. * child commit is popped from the lowest level of walk's internal graph.
  1208. *
  1209. * @param flag
  1210. * the flag to carry onto parents, if set on a descendant.
  1211. */
  1212. public void carry(RevFlag flag) {
  1213. if ((freeFlags & flag.mask) != 0)
  1214. throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
  1215. if (flag.walker != this)
  1216. throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagNotFromThis, flag.name));
  1217. carryFlags |= flag.mask;
  1218. }
  1219. /**
  1220. * Automatically carry flags from a child commit to its parents.
  1221. * <p>
  1222. * A carried flag is copied from the child commit onto its parents when the
  1223. * child commit is popped from the lowest level of walk's internal graph.
  1224. *
  1225. * @param set
  1226. * the flags to carry onto parents, if set on a descendant.
  1227. */
  1228. public void carry(Collection<RevFlag> set) {
  1229. for (RevFlag flag : set)
  1230. carry(flag);
  1231. }
  1232. /**
  1233. * Preserve a RevFlag during all {@code reset} methods.
  1234. * <p>
  1235. * Calling {@code retainOnReset(flag)} avoids needing to pass the flag
  1236. * during each {@code resetRetain()} invocation on this instance.
  1237. * <p>
  1238. * Clearing flags marked retainOnReset requires disposing of the flag with
  1239. * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
  1240. * {@code #dispose()}.
  1241. *
  1242. * @param flag
  1243. * the flag to retain during all resets.
  1244. * @since 3.6
  1245. */
  1246. public final void retainOnReset(RevFlag flag) {
  1247. if ((freeFlags & flag.mask) != 0)
  1248. throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagIsDisposed, flag.name));
  1249. if (flag.walker != this)
  1250. throw new IllegalArgumentException(MessageFormat.format(JGitText.get().flagNotFromThis, flag.name));
  1251. retainOnReset |= flag.mask;
  1252. }
  1253. /**
  1254. * Preserve a set of RevFlags during all {@code reset} methods.
  1255. * <p>
  1256. * Calling {@code retainOnReset(set)} avoids needing to pass the flags
  1257. * during each {@code resetRetain()} invocation on this instance.
  1258. * <p>
  1259. * Clearing flags marked retainOnReset requires disposing of the flag with
  1260. * {@code #disposeFlag(RevFlag)} or disposing of the entire RevWalk by
  1261. * {@code #dispose()}.
  1262. *
  1263. * @param flags
  1264. * the flags to retain during all resets.
  1265. * @since 3.6
  1266. */
  1267. public final void retainOnReset(Collection<RevFlag> flags) {
  1268. for (RevFlag f : flags)
  1269. retainOnReset(f);
  1270. }
  1271. /**
  1272. * Allow a flag to be recycled for a different use.
  1273. * <p>
  1274. * Recycled flags always come back as a different Java object instance when
  1275. * assigned again by {@link #newFlag(String)}.
  1276. * <p>
  1277. * If the flag was previously being carried, the carrying request is
  1278. * removed. Disposing of a carried flag while a traversal is in progress has
  1279. * an undefined behavior.
  1280. *
  1281. * @param flag
  1282. * the to recycle.
  1283. */
  1284. public void disposeFlag(RevFlag flag) {
  1285. freeFlag(flag.mask);
  1286. }
  1287. void freeFlag(int mask) {
  1288. retainOnReset &= ~mask;
  1289. if (isNotStarted()) {
  1290. freeFlags |= mask;
  1291. carryFlags &= ~mask;
  1292. } else {
  1293. delayFreeFlags |= mask;
  1294. }
  1295. }
  1296. private void finishDelayedFreeFlags() {
  1297. if (delayFreeFlags != 0) {
  1298. freeFlags |= delayFreeFlags;
  1299. carryFlags &= ~delayFreeFlags;
  1300. delayFreeFlags = 0;
  1301. }
  1302. }
  1303. /**
  1304. * Resets internal state and allows this instance to be used again.
  1305. * <p>
  1306. * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
  1307. * instances are not invalidated. RevFlag instances are not invalidated, but
  1308. * are removed from all RevObjects.
  1309. */
  1310. public final void reset() {
  1311. reset(0);
  1312. }
  1313. /**
  1314. * Resets internal state and allows this instance to be used again.
  1315. * <p>
  1316. * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
  1317. * instances are not invalidated. RevFlag instances are not invalidated, but
  1318. * are removed from all RevObjects.
  1319. *
  1320. * @param retainFlags
  1321. * application flags that should <b>not</b> be cleared from
  1322. * existing commit objects.
  1323. */
  1324. public final void resetRetain(RevFlagSet retainFlags) {
  1325. reset(retainFlags.mask);
  1326. }
  1327. /**
  1328. * Resets internal state and allows this instance to be used again.
  1329. * <p>
  1330. * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
  1331. * instances are not invalidated. RevFlag instances are not invalidated, but
  1332. * are removed from all RevObjects.
  1333. * <p>
  1334. * See {@link #retainOnReset(RevFlag)} for an alternative that does not
  1335. * require passing the flags during each reset.
  1336. *
  1337. * @param retainFlags
  1338. * application flags that should <b>not</b> be cleared from
  1339. * existing commit objects.
  1340. */
  1341. public final void resetRetain(RevFlag... retainFlags) {
  1342. int mask = 0;
  1343. for (RevFlag flag : retainFlags)
  1344. mask |= flag.mask;
  1345. reset(mask);
  1346. }
  1347. /**
  1348. * Resets internal state and allows this instance to be used again.
  1349. * <p>
  1350. * Unlike {@link #dispose()} previously acquired RevObject (and RevCommit)
  1351. * instances are not invalidated. RevFlag instances are not invalidated, but
  1352. * are removed from all RevObjects. The value of {@code firstParent} is
  1353. * retained.
  1354. *
  1355. * @param retainFlags
  1356. * application flags that should <b>not</b> be cleared from
  1357. * existing commit objects.
  1358. */
  1359. protected void reset(int retainFlags) {
  1360. finishDelayedFreeFlags();
  1361. retainFlags |= PARSED | retainOnReset;
  1362. final int clearFlags = ~retainFlags;
  1363. final FIFORevQueue q = new FIFORevQueue();
  1364. for (RevCommit c : roots) {
  1365. if ((c.flags & clearFlags) == 0)
  1366. continue;
  1367. c.flags &= retainFlags;
  1368. c.reset();
  1369. q.add(c);
  1370. }
  1371. for (;;) {
  1372. final RevCommit c = q.next();
  1373. if (c == null)
  1374. break;
  1375. if (c.parents == null)
  1376. continue;
  1377. for (RevCommit p : c.parents) {
  1378. if ((p.flags & clearFlags) == 0)
  1379. continue;
  1380. p.flags &= retainFlags;
  1381. p.reset();
  1382. q.add(p);
  1383. }
  1384. }
  1385. roots.clear();
  1386. queue = new DateRevQueue(firstParent);
  1387. pending = new StartGenerator(this);
  1388. }
  1389. /**
  1390. * Dispose all internal state and invalidate all RevObject instances.
  1391. * <p>
  1392. * All RevObject (and thus RevCommit, etc.) instances previously acquired
  1393. * from this RevWalk are invalidated by a dispose call. Applications must
  1394. * not retain or use RevObject instances obtained prior to the dispose call.
  1395. * All RevFlag instances are also invalidated, and must not be reused.
  1396. */
  1397. public void dispose() {
  1398. reader.close();
  1399. freeFlags = APP_FLAGS;
  1400. delayFreeFlags = 0;
  1401. retainOnReset = 0;
  1402. carryFlags = UNINTERESTING;
  1403. firstParent = false;
  1404. objects.clear();
  1405. roots.clear();
  1406. queue = new DateRevQueue(firstParent);
  1407. pending = new StartGenerator(this);
  1408. shallowCommitsInitialized = false;
  1409. }
  1410. /**
  1411. * Like {@link #next()}, but if a checked exception is thrown during the
  1412. * walk it is rethrown as a {@link RevWalkException}.
  1413. *
  1414. * @throws RevWalkException if an {@link IOException} was thrown.
  1415. * @return next most recent commit; null if traversal is over.
  1416. */
  1417. @Nullable
  1418. private RevCommit nextForIterator() {
  1419. try {
  1420. return next();
  1421. } catch (IOException e) {
  1422. throw new RevWalkException(e);
  1423. }
  1424. }
  1425. /**
  1426. * {@inheritDoc}
  1427. * <p>
  1428. * Returns an Iterator over the commits of this walker.
  1429. * <p>
  1430. * The returned iterator is only useful for one walk. If this RevWalk gets
  1431. * reset a new iterator must be obtained to walk over the new results.
  1432. * <p>
  1433. * Applications must not use both the Iterator and the {@link #next()} API
  1434. * at the same time. Pick one API and use that for the entire walk.
  1435. * <p>
  1436. * If a checked exception is thrown during the walk (see {@link #next()}) it
  1437. * is rethrown from the Iterator as a {@link RevWalkException}.
  1438. *
  1439. * @see RevWalkException
  1440. */
  1441. @Override
  1442. public Iterator<RevCommit> iterator() {
  1443. RevCommit first = nextForIterator();
  1444. return new Iterator<RevCommit>() {
  1445. RevCommit next = first;
  1446. @Override
  1447. public boolean hasNext() {
  1448. return next != null;
  1449. }
  1450. @Override
  1451. public RevCommit next() {
  1452. RevCommit r = next;
  1453. next = nextForIterator();
  1454. return r;
  1455. }
  1456. @Override
  1457. public void remove() {
  1458. throw new UnsupportedOperationException();
  1459. }
  1460. };
  1461. }
  1462. /**
  1463. * Throws an exception if we have started producing output.
  1464. */
  1465. protected void assertNotStarted() {
  1466. if (isNotStarted())
  1467. return;
  1468. throw new IllegalStateException(JGitText.get().outputHasAlreadyBeenStarted);
  1469. }
  1470. /**
  1471. * Throws an exception if any commits have been marked as start.
  1472. * <p>
  1473. * If {@link #markStart(RevCommit)} has already been called,
  1474. * {@link #reset()} can be called to satisfy this condition.
  1475. *
  1476. * @since 5.5
  1477. */
  1478. protected void assertNoCommitsMarkedStart() {
  1479. if (roots.isEmpty())
  1480. return;
  1481. throw new IllegalStateException(
  1482. JGitText.get().commitsHaveAlreadyBeenMarkedAsStart);
  1483. }
  1484. private boolean isNotStarted() {
  1485. return pending instanceof StartGenerator;
  1486. }
  1487. /**
  1488. * Create and return an {@link org.eclipse.jgit.revwalk.ObjectWalk} using
  1489. * the same objects.
  1490. * <p>
  1491. * Prior to using this method, the caller must reset this RevWalk to clean
  1492. * any flags that were used during the last traversal.
  1493. * <p>
  1494. * The returned ObjectWalk uses the same ObjectReader, internal object pool,
  1495. * and free RevFlags. Once the ObjectWalk is created, this RevWalk should
  1496. * not be used anymore.
  1497. *
  1498. * @return a new walk, using the exact same object pool.
  1499. */
  1500. public ObjectWalk toObjectWalkWithSameObjects() {
  1501. ObjectWalk ow = new ObjectWalk(reader);
  1502. RevWalk rw = ow;
  1503. rw.objects = objects;
  1504. rw.freeFlags = freeFlags;
  1505. return ow;
  1506. }
  1507. /**
  1508. * Construct a new unparsed commit for the given object.
  1509. *
  1510. * @param id
  1511. * the object this walker requires a commit reference for.
  1512. * @return a new unparsed reference for the object.
  1513. */
  1514. protected RevCommit createCommit(AnyObjectId id) {
  1515. return new RevCommit(id);
  1516. }
  1517. void carryFlagsImpl(RevCommit c) {
  1518. final int carry = c.flags & carryFlags;
  1519. if (carry != 0)
  1520. RevCommit.carryFlags(c, carry);
  1521. }
  1522. /**
  1523. * Assume additional commits are shallow (have no parents).
  1524. * <p>
  1525. * This method is a No-op if the collection is empty.
  1526. *
  1527. * @param ids
  1528. * commits that should be treated as shallow commits, in addition
  1529. * to any commits already known to be shallow by the repository.
  1530. * @since 3.3
  1531. */
  1532. public void assumeShallow(Collection<? extends ObjectId> ids) {
  1533. for (ObjectId id : ids)
  1534. lookupCommit(id).parents = RevCommit.NO_PARENTS;
  1535. }
  1536. /**
  1537. * Reads the "shallow" file and applies it by setting the parents of shallow
  1538. * commits to an empty array.
  1539. * <p>
  1540. * There is a sequencing problem if the first commit being parsed is a
  1541. * shallow commit, since {@link RevCommit#parseCanonical(RevWalk, byte[])}
  1542. * calls this method before its callers add the new commit to the
  1543. * {@link RevWalk#objects} map. That means a call from this method to
  1544. * {@link #lookupCommit(AnyObjectId)} fails to find that commit and creates
  1545. * a new one, which is promptly discarded.
  1546. * <p>
  1547. * To avoid that, {@link RevCommit#parseCanonical(RevWalk, byte[])} passes
  1548. * its commit to this method, so that this method can apply the shallow
  1549. * state to it directly and avoid creating the duplicate commit object.
  1550. *
  1551. * @param rc
  1552. * the initial commit being parsed
  1553. * @throws IOException
  1554. * if the shallow commits file can't be read
  1555. */
  1556. void initializeShallowCommits(RevCommit rc) throws IOException {
  1557. if (shallowCommitsInitialized) {
  1558. throw new IllegalStateException(
  1559. JGitText.get().shallowCommitsAlreadyInitialized);
  1560. }
  1561. shallowCommitsInitialized = true;
  1562. if (reader == null) {
  1563. return;
  1564. }
  1565. for (ObjectId id : reader.getShallowCommits()) {
  1566. if (id.equals(rc.getId())) {
  1567. rc.parents = RevCommit.NO_PARENTS;
  1568. } else {
  1569. lookupCommit(id).parents = RevCommit.NO_PARENTS;
  1570. }
  1571. }
  1572. }
  1573. }