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 48KB

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