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.

RevCommit.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. * Copyright (C) 2008-2009, Google Inc.
  3. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
  4. *
  5. * This program and the accompanying materials are made available under the
  6. * terms of the Eclipse Distribution License v. 1.0 which is available at
  7. * https://www.eclipse.org/org/documents/edl-v10.php.
  8. *
  9. * SPDX-License-Identifier: BSD-3-Clause
  10. */
  11. package org.eclipse.jgit.revwalk;
  12. import static java.nio.charset.StandardCharsets.UTF_8;
  13. import java.io.IOException;
  14. import java.nio.charset.Charset;
  15. import java.nio.charset.IllegalCharsetNameException;
  16. import java.nio.charset.UnsupportedCharsetException;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Collections;
  20. import java.util.List;
  21. import org.eclipse.jgit.annotations.Nullable;
  22. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  23. import org.eclipse.jgit.errors.MissingObjectException;
  24. import org.eclipse.jgit.lib.AnyObjectId;
  25. import org.eclipse.jgit.lib.Constants;
  26. import org.eclipse.jgit.lib.MutableObjectId;
  27. import org.eclipse.jgit.lib.ObjectInserter;
  28. import org.eclipse.jgit.lib.ObjectReader;
  29. import org.eclipse.jgit.lib.PersonIdent;
  30. import org.eclipse.jgit.util.RawParseUtils;
  31. import org.eclipse.jgit.util.StringUtils;
  32. /**
  33. * A commit reference to a commit in the DAG.
  34. */
  35. public class RevCommit extends RevObject {
  36. private static final int STACK_DEPTH = 500;
  37. /**
  38. * Parse a commit from its canonical format.
  39. *
  40. * This method constructs a temporary revision pool, parses the commit as
  41. * supplied, and returns it to the caller. Since the commit was built inside
  42. * of a private revision pool its parent pointers will be initialized, but
  43. * will not have their headers loaded.
  44. *
  45. * Applications are discouraged from using this API. Callers usually need
  46. * more than one commit. Use
  47. * {@link org.eclipse.jgit.revwalk.RevWalk#parseCommit(AnyObjectId)} to
  48. * obtain a RevCommit from an existing repository.
  49. *
  50. * @param raw
  51. * the canonical formatted commit to be parsed.
  52. * @return the parsed commit, in an isolated revision pool that is not
  53. * available to the caller.
  54. */
  55. public static RevCommit parse(byte[] raw) {
  56. try {
  57. return parse(new RevWalk((ObjectReader) null), raw);
  58. } catch (IOException ex) {
  59. throw new RuntimeException(ex);
  60. }
  61. }
  62. /**
  63. * Parse a commit from its canonical format.
  64. * <p>
  65. * This method inserts the commit directly into the caller supplied revision
  66. * pool, making it appear as though the commit exists in the repository,
  67. * even if it doesn't. The repository under the pool is not affected.
  68. * <p>
  69. * The body of the commit (message, author, committer) is always retained in
  70. * the returned {@code RevCommit}, even if the supplied {@code RevWalk} has
  71. * been configured with {@code setRetainBody(false)}.
  72. *
  73. * @param rw
  74. * the revision pool to allocate the commit within. The commit's
  75. * tree and parent pointers will be obtained from this pool.
  76. * @param raw
  77. * the canonical formatted commit to be parsed. This buffer will
  78. * be retained by the returned {@code RevCommit} and must not be
  79. * modified by the caller.
  80. * @return the parsed commit, in an isolated revision pool that is not
  81. * available to the caller.
  82. * @throws java.io.IOException
  83. * in case of RevWalk initialization fails
  84. */
  85. public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException {
  86. try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
  87. RevCommit r = rw.lookupCommit(fmt.idFor(Constants.OBJ_COMMIT, raw));
  88. r.parseCanonical(rw, raw);
  89. r.buffer = raw;
  90. return r;
  91. }
  92. }
  93. static final RevCommit[] NO_PARENTS = {};
  94. private RevTree tree;
  95. RevCommit[] parents;
  96. int commitTime; // An int here for performance, overflows in 2038
  97. int inDegree;
  98. private byte[] buffer;
  99. /**
  100. * Create a new commit reference.
  101. *
  102. * @param id
  103. * object name for the commit.
  104. */
  105. protected RevCommit(AnyObjectId id) {
  106. super(id);
  107. }
  108. @Override
  109. void parseHeaders(RevWalk walk) throws MissingObjectException,
  110. IncorrectObjectTypeException, IOException {
  111. parseCanonical(walk, walk.getCachedBytes(this));
  112. }
  113. @Override
  114. void parseBody(RevWalk walk) throws MissingObjectException,
  115. IncorrectObjectTypeException, IOException {
  116. if (buffer == null) {
  117. buffer = walk.getCachedBytes(this);
  118. if ((flags & PARSED) == 0)
  119. parseCanonical(walk, buffer);
  120. }
  121. }
  122. void parseCanonical(RevWalk walk, byte[] raw) throws IOException {
  123. if (!walk.shallowCommitsInitialized) {
  124. walk.initializeShallowCommits(this);
  125. }
  126. final MutableObjectId idBuffer = walk.idBuffer;
  127. idBuffer.fromString(raw, 5);
  128. tree = walk.lookupTree(idBuffer);
  129. int ptr = 46;
  130. if (parents == null) {
  131. RevCommit[] pList = new RevCommit[1];
  132. int nParents = 0;
  133. for (;;) {
  134. if (raw[ptr] != 'p') {
  135. break;
  136. }
  137. idBuffer.fromString(raw, ptr + 7);
  138. final RevCommit p = walk.lookupCommit(idBuffer);
  139. switch (nParents) {
  140. case 0:
  141. pList[nParents++] = p;
  142. break;
  143. case 1:
  144. pList = new RevCommit[] { pList[0], p };
  145. nParents = 2;
  146. break;
  147. default:
  148. if (pList.length <= nParents) {
  149. RevCommit[] old = pList;
  150. pList = new RevCommit[pList.length + 32];
  151. System.arraycopy(old, 0, pList, 0, nParents);
  152. }
  153. pList[nParents++] = p;
  154. break;
  155. }
  156. ptr += 48;
  157. }
  158. if (nParents != pList.length) {
  159. RevCommit[] old = pList;
  160. pList = new RevCommit[nParents];
  161. System.arraycopy(old, 0, pList, 0, nParents);
  162. }
  163. parents = pList;
  164. }
  165. // extract time from "committer "
  166. ptr = RawParseUtils.committer(raw, ptr);
  167. if (ptr > 0) {
  168. ptr = RawParseUtils.nextLF(raw, ptr, '>');
  169. // In 2038 commitTime will overflow unless it is changed to long.
  170. commitTime = RawParseUtils.parseBase10(raw, ptr, null);
  171. }
  172. if (walk.isRetainBody()) {
  173. buffer = raw;
  174. }
  175. flags |= PARSED;
  176. }
  177. /** {@inheritDoc} */
  178. @Override
  179. public final int getType() {
  180. return Constants.OBJ_COMMIT;
  181. }
  182. static void carryFlags(RevCommit c, int carry) {
  183. FIFORevQueue q = carryFlags1(c, carry, 0);
  184. if (q != null)
  185. slowCarryFlags(q, carry);
  186. }
  187. private static FIFORevQueue carryFlags1(RevCommit c, int carry, int depth) {
  188. for(;;) {
  189. RevCommit[] pList = c.parents;
  190. if (pList == null || pList.length == 0)
  191. return null;
  192. if (pList.length != 1) {
  193. if (depth == STACK_DEPTH)
  194. return defer(c);
  195. for (int i = 1; i < pList.length; i++) {
  196. RevCommit p = pList[i];
  197. if ((p.flags & carry) == carry)
  198. continue;
  199. p.flags |= carry;
  200. FIFORevQueue q = carryFlags1(p, carry, depth + 1);
  201. if (q != null)
  202. return defer(q, carry, pList, i + 1);
  203. }
  204. }
  205. c = pList[0];
  206. if ((c.flags & carry) == carry)
  207. return null;
  208. c.flags |= carry;
  209. }
  210. }
  211. private static FIFORevQueue defer(RevCommit c) {
  212. FIFORevQueue q = new FIFORevQueue();
  213. q.add(c);
  214. return q;
  215. }
  216. private static FIFORevQueue defer(FIFORevQueue q, int carry,
  217. RevCommit[] pList, int i) {
  218. // In normal case the caller will run pList[0] in a tail recursive
  219. // fashion by updating the variable. However the caller is unwinding
  220. // the stack and will skip that pList[0] execution step.
  221. carryOneStep(q, carry, pList[0]);
  222. // Remaining parents (if any) need to have flags checked and be
  223. // enqueued if they have ancestors.
  224. for (; i < pList.length; i++)
  225. carryOneStep(q, carry, pList[i]);
  226. return q;
  227. }
  228. private static void slowCarryFlags(FIFORevQueue q, int carry) {
  229. // Commits in q have non-null parent arrays and have set all
  230. // flags in carry. This loop finishes copying over the graph.
  231. for (RevCommit c; (c = q.next()) != null;) {
  232. for (RevCommit p : c.parents)
  233. carryOneStep(q, carry, p);
  234. }
  235. }
  236. private static void carryOneStep(FIFORevQueue q, int carry, RevCommit c) {
  237. if ((c.flags & carry) != carry) {
  238. c.flags |= carry;
  239. if (c.parents != null)
  240. q.add(c);
  241. }
  242. }
  243. /**
  244. * Carry a RevFlag set on this commit to its parents.
  245. * <p>
  246. * If this commit is parsed, has parents, and has the supplied flag set on
  247. * it we automatically add it to the parents, grand-parents, and so on until
  248. * an unparsed commit or a commit with no parents is discovered. This
  249. * permits applications to force a flag through the history chain when
  250. * necessary.
  251. *
  252. * @param flag
  253. * the single flag value to carry back onto parents.
  254. */
  255. public void carry(RevFlag flag) {
  256. final int carry = flags & flag.mask;
  257. if (carry != 0)
  258. carryFlags(this, carry);
  259. }
  260. /**
  261. * Time from the "committer " line of the buffer.
  262. *
  263. * @return commit time
  264. */
  265. public final int getCommitTime() {
  266. return commitTime;
  267. }
  268. /**
  269. * Get a reference to this commit's tree.
  270. *
  271. * @return tree of this commit.
  272. */
  273. public final RevTree getTree() {
  274. return tree;
  275. }
  276. /**
  277. * Get the number of parent commits listed in this commit.
  278. *
  279. * @return number of parents; always a positive value but can be 0.
  280. */
  281. public final int getParentCount() {
  282. return parents.length;
  283. }
  284. /**
  285. * Get the nth parent from this commit's parent list.
  286. *
  287. * @param nth
  288. * parent index to obtain. Must be in the range 0 through
  289. * {@link #getParentCount()}-1.
  290. * @return the specified parent.
  291. * @throws java.lang.ArrayIndexOutOfBoundsException
  292. * an invalid parent index was specified.
  293. */
  294. public final RevCommit getParent(int nth) {
  295. return parents[nth];
  296. }
  297. /**
  298. * Obtain an array of all parents (<b>NOTE - THIS IS NOT A COPY</b>).
  299. * <p>
  300. * This method is exposed only to provide very fast, efficient access to
  301. * this commit's parent list. Applications relying on this list should be
  302. * very careful to ensure they do not modify its contents during their use
  303. * of it.
  304. *
  305. * @return the array of parents.
  306. */
  307. public final RevCommit[] getParents() {
  308. return parents;
  309. }
  310. /**
  311. * Obtain the raw unparsed commit body (<b>NOTE - THIS IS NOT A COPY</b>).
  312. * <p>
  313. * This method is exposed only to provide very fast, efficient access to
  314. * this commit's message buffer within a RevFilter. Applications relying on
  315. * this buffer should be very careful to ensure they do not modify its
  316. * contents during their use of it.
  317. *
  318. * @return the raw unparsed commit body. This is <b>NOT A COPY</b>.
  319. * Altering the contents of this buffer may alter the walker's
  320. * knowledge of this commit, and the results it produces.
  321. */
  322. public final byte[] getRawBuffer() {
  323. return buffer;
  324. }
  325. /**
  326. * Parse the gpg signature from the raw buffer.
  327. * <p>
  328. * This method parses and returns the raw content of the gpgsig lines. This
  329. * method is fairly expensive and produces a new byte[] instance on each
  330. * invocation. Callers should invoke this method only if they are certain
  331. * they will need, and should cache the return value for as long as
  332. * necessary to use all information from it.
  333. * <p>
  334. * RevFilter implementations should try to use
  335. * {@link org.eclipse.jgit.util.RawParseUtils} to scan the
  336. * {@link #getRawBuffer()} instead, as this will allow faster evaluation of
  337. * commits.
  338. *
  339. * @return contents of the gpg signature; null if the commit was not signed.
  340. * @since 5.1
  341. */
  342. public final byte[] getRawGpgSignature() {
  343. final byte[] raw = buffer;
  344. final byte[] header = {'g', 'p', 'g', 's', 'i', 'g'};
  345. final int start = RawParseUtils.headerStart(header, raw, 0);
  346. if (start < 0) {
  347. return null;
  348. }
  349. final int end = RawParseUtils.headerEnd(raw, start);
  350. return Arrays.copyOfRange(raw, start, end);
  351. }
  352. /**
  353. * Parse the author identity from the raw buffer.
  354. * <p>
  355. * This method parses and returns the content of the author line, after
  356. * taking the commit's character set into account and decoding the author
  357. * name and email address. This method is fairly expensive and produces a
  358. * new PersonIdent instance on each invocation. Callers should invoke this
  359. * method only if they are certain they will be outputting the result, and
  360. * should cache the return value for as long as necessary to use all
  361. * information from it.
  362. * <p>
  363. * RevFilter implementations should try to use
  364. * {@link org.eclipse.jgit.util.RawParseUtils} to scan the
  365. * {@link #getRawBuffer()} instead, as this will allow faster evaluation of
  366. * commits.
  367. *
  368. * @return identity of the author (name, email) and the time the commit was
  369. * made by the author; null if no author line was found.
  370. */
  371. public final PersonIdent getAuthorIdent() {
  372. final byte[] raw = buffer;
  373. final int nameB = RawParseUtils.author(raw, 0);
  374. if (nameB < 0)
  375. return null;
  376. return RawParseUtils.parsePersonIdent(raw, nameB);
  377. }
  378. /**
  379. * Parse the committer identity from the raw buffer.
  380. * <p>
  381. * This method parses and returns the content of the committer line, after
  382. * taking the commit's character set into account and decoding the committer
  383. * name and email address. This method is fairly expensive and produces a
  384. * new PersonIdent instance on each invocation. Callers should invoke this
  385. * method only if they are certain they will be outputting the result, and
  386. * should cache the return value for as long as necessary to use all
  387. * information from it.
  388. * <p>
  389. * RevFilter implementations should try to use
  390. * {@link org.eclipse.jgit.util.RawParseUtils} to scan the
  391. * {@link #getRawBuffer()} instead, as this will allow faster evaluation of
  392. * commits.
  393. *
  394. * @return identity of the committer (name, email) and the time the commit
  395. * was made by the committer; null if no committer line was found.
  396. */
  397. public final PersonIdent getCommitterIdent() {
  398. final byte[] raw = buffer;
  399. final int nameB = RawParseUtils.committer(raw, 0);
  400. if (nameB < 0)
  401. return null;
  402. return RawParseUtils.parsePersonIdent(raw, nameB);
  403. }
  404. /**
  405. * Parse the complete commit message and decode it to a string.
  406. * <p>
  407. * This method parses and returns the message portion of the commit buffer,
  408. * after taking the commit's character set into account and decoding the
  409. * buffer using that character set. This method is a fairly expensive
  410. * operation and produces a new string on each invocation.
  411. *
  412. * @return decoded commit message as a string. Never null.
  413. */
  414. public final String getFullMessage() {
  415. byte[] raw = buffer;
  416. int msgB = RawParseUtils.commitMessage(raw, 0);
  417. if (msgB < 0) {
  418. return ""; //$NON-NLS-1$
  419. }
  420. return RawParseUtils.decode(guessEncoding(), raw, msgB, raw.length);
  421. }
  422. /**
  423. * Parse the commit message and return the first "line" of it.
  424. * <p>
  425. * The first line is everything up to the first pair of LFs. This is the
  426. * "oneline" format, suitable for output in a single line display.
  427. * <p>
  428. * This method parses and returns the message portion of the commit buffer,
  429. * after taking the commit's character set into account and decoding the
  430. * buffer using that character set. This method is a fairly expensive
  431. * operation and produces a new string on each invocation.
  432. *
  433. * @return decoded commit message as a string. Never null. The returned
  434. * string does not contain any LFs, even if the first paragraph
  435. * spanned multiple lines. Embedded LFs are converted to spaces.
  436. */
  437. public final String getShortMessage() {
  438. byte[] raw = buffer;
  439. int msgB = RawParseUtils.commitMessage(raw, 0);
  440. if (msgB < 0) {
  441. return ""; //$NON-NLS-1$
  442. }
  443. int msgE = RawParseUtils.endOfParagraph(raw, msgB);
  444. String str = RawParseUtils.decode(guessEncoding(), raw, msgB, msgE);
  445. if (hasLF(raw, msgB, msgE)) {
  446. str = StringUtils.replaceLineBreaksWithSpace(str);
  447. }
  448. return str;
  449. }
  450. static boolean hasLF(byte[] r, int b, int e) {
  451. while (b < e)
  452. if (r[b++] == '\n')
  453. return true;
  454. return false;
  455. }
  456. /**
  457. * Determine the encoding of the commit message buffer.
  458. * <p>
  459. * Locates the "encoding" header (if present) and returns its value. Due to
  460. * corruption in the wild this may be an invalid encoding name that is not
  461. * recognized by any character encoding library.
  462. * <p>
  463. * If no encoding header is present, null.
  464. *
  465. * @return the preferred encoding of {@link #getRawBuffer()}; or null.
  466. * @since 4.2
  467. */
  468. @Nullable
  469. public final String getEncodingName() {
  470. return RawParseUtils.parseEncodingName(buffer);
  471. }
  472. /**
  473. * Determine the encoding of the commit message buffer.
  474. * <p>
  475. * Locates the "encoding" header (if present) and then returns the proper
  476. * character set to apply to this buffer to evaluate its contents as
  477. * character data.
  478. * <p>
  479. * If no encoding header is present {@code UTF-8} is assumed.
  480. *
  481. * @return the preferred encoding of {@link #getRawBuffer()}.
  482. * @throws IllegalCharsetNameException
  483. * if the character set requested by the encoding header is
  484. * malformed and unsupportable.
  485. * @throws UnsupportedCharsetException
  486. * if the JRE does not support the character set requested by
  487. * the encoding header.
  488. */
  489. public final Charset getEncoding() {
  490. return RawParseUtils.parseEncoding(buffer);
  491. }
  492. private Charset guessEncoding() {
  493. try {
  494. return getEncoding();
  495. } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
  496. return UTF_8;
  497. }
  498. }
  499. /**
  500. * Parse the footer lines (e.g. "Signed-off-by") for machine processing.
  501. * <p>
  502. * This method splits all of the footer lines out of the last paragraph of
  503. * the commit message, providing each line as a key-value pair, ordered by
  504. * the order of the line's appearance in the commit message itself.
  505. * <p>
  506. * A footer line's key must match the pattern {@code ^[A-Za-z0-9-]+:}, while
  507. * the value is free-form, but must not contain an LF. Very common keys seen
  508. * in the wild are:
  509. * <ul>
  510. * <li>{@code Signed-off-by} (agrees to Developer Certificate of Origin)
  511. * <li>{@code Acked-by} (thinks change looks sane in context)
  512. * <li>{@code Reported-by} (originally found the issue this change fixes)
  513. * <li>{@code Tested-by} (validated change fixes the issue for them)
  514. * <li>{@code CC}, {@code Cc} (copy on all email related to this change)
  515. * <li>{@code Bug} (link to project's bug tracking system)
  516. * </ul>
  517. *
  518. * @return ordered list of footer lines; empty list if no footers found.
  519. */
  520. public final List<FooterLine> getFooterLines() {
  521. final byte[] raw = buffer;
  522. int ptr = raw.length - 1;
  523. while (raw[ptr] == '\n') // trim any trailing LFs, not interesting
  524. ptr--;
  525. final int msgB = RawParseUtils.commitMessage(raw, 0);
  526. final ArrayList<FooterLine> r = new ArrayList<>(4);
  527. final Charset enc = guessEncoding();
  528. for (;;) {
  529. ptr = RawParseUtils.prevLF(raw, ptr);
  530. if (ptr <= msgB)
  531. break; // Don't parse commit headers as footer lines.
  532. final int keyStart = ptr + 2;
  533. if (raw[keyStart] == '\n')
  534. break; // Stop at first paragraph break, no footers above it.
  535. final int keyEnd = RawParseUtils.endOfFooterLineKey(raw, keyStart);
  536. if (keyEnd < 0)
  537. continue; // Not a well formed footer line, skip it.
  538. // Skip over the ': *' at the end of the key before the value.
  539. //
  540. int valStart = keyEnd + 1;
  541. while (valStart < raw.length && raw[valStart] == ' ')
  542. valStart++;
  543. // Value ends at the LF, and does not include it.
  544. //
  545. int valEnd = RawParseUtils.nextLF(raw, valStart);
  546. if (raw[valEnd - 1] == '\n')
  547. valEnd--;
  548. r.add(new FooterLine(raw, enc, keyStart, keyEnd, valStart, valEnd));
  549. }
  550. Collections.reverse(r);
  551. return r;
  552. }
  553. /**
  554. * Get the values of all footer lines with the given key.
  555. *
  556. * @param keyName
  557. * footer key to find values of, case insensitive.
  558. * @return values of footers with key of {@code keyName}, ordered by their
  559. * order of appearance. Duplicates may be returned if the same
  560. * footer appeared more than once. Empty list if no footers appear
  561. * with the specified key, or there are no footers at all.
  562. * @see #getFooterLines()
  563. */
  564. public final List<String> getFooterLines(String keyName) {
  565. return getFooterLines(new FooterKey(keyName));
  566. }
  567. /**
  568. * Get the values of all footer lines with the given key.
  569. *
  570. * @param keyName
  571. * footer key to find values of, case insensitive.
  572. * @return values of footers with key of {@code keyName}, ordered by their
  573. * order of appearance. Duplicates may be returned if the same
  574. * footer appeared more than once. Empty list if no footers appear
  575. * with the specified key, or there are no footers at all.
  576. * @see #getFooterLines()
  577. */
  578. public final List<String> getFooterLines(FooterKey keyName) {
  579. final List<FooterLine> src = getFooterLines();
  580. if (src.isEmpty())
  581. return Collections.emptyList();
  582. final ArrayList<String> r = new ArrayList<>(src.size());
  583. for (FooterLine f : src) {
  584. if (f.matches(keyName))
  585. r.add(f.getValue());
  586. }
  587. return r;
  588. }
  589. /**
  590. * Reset this commit to allow another RevWalk with the same instances.
  591. * <p>
  592. * Subclasses <b>must</b> call <code>super.reset()</code> to ensure the
  593. * basic information can be correctly cleared out.
  594. */
  595. public void reset() {
  596. inDegree = 0;
  597. }
  598. /**
  599. * Discard the message buffer to reduce memory usage.
  600. * <p>
  601. * After discarding the memory usage of the {@code RevCommit} is reduced to
  602. * only the {@link #getTree()} and {@link #getParents()} pointers and the
  603. * time in {@link #getCommitTime()}. Accessing other properties such as
  604. * {@link #getAuthorIdent()}, {@link #getCommitterIdent()} or either message
  605. * function requires reloading the buffer by invoking
  606. * {@link org.eclipse.jgit.revwalk.RevWalk#parseBody(RevObject)}.
  607. *
  608. * @since 4.0
  609. */
  610. public final void disposeBody() {
  611. buffer = null;
  612. }
  613. /** {@inheritDoc} */
  614. @Override
  615. public String toString() {
  616. final StringBuilder s = new StringBuilder();
  617. s.append(Constants.typeString(getType()));
  618. s.append(' ');
  619. s.append(name());
  620. s.append(' ');
  621. s.append(commitTime);
  622. s.append(' ');
  623. appendCoreFlags(s);
  624. return s.toString();
  625. }
  626. }